使用HorizontalScrollView实现侧滑菜单
2015-04-05 12:42
477 查看
主要继承 HorizontalScrollView 类 ,在构造方法中设置 菜单的宽, 重写 onMeasure, onLayout 方法 ,在 onLayout 中设置初始显示到 内容页的 scrollTo , 一个高级的安卓开发必须熟练掌握 自定义的用法, View的绘制原理。
准备知识:
a. 四舍五入的代码就是把结果加上0.5f再进行强制转换
b. getDimension()是基于当前DisplayMetrics进行转换,获取指定资源id对应的尺寸。文档里并没说这里返回的就是像素,要注意这个函数的返回值是float,像素肯定是int。
getDimensionPixelSize()与getDimension()功能类似,不同的是将结果转换为int,并且小数部分四舍五入。
getDimensionPixelOffset()与getDimension()功能类似,不同的是将结果转换为int,并且偏移转换(offset conversion,函数命名中的offset是这个意思)是直接截断小数位,即取整(其实就是把float强制转化为int,注意不是四舍五入哦)。
1、SlidingMenuView 类的实现如下,
package com.example.slidingmenu;
import com.nineoldandroids.view.ViewHelper;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
public class SlidingMenuView extends HorizontalScrollView {
/*
* 1、书写自定义属性的 attr.xml 属性 </br> 2、使用时引入 xmlns命名空间 3、在构造方法中获得我们设置的值
*/
private LinearLayout mWapper;
private ViewGroup mMenu;
private ViewGroup mContent;
private int mScreenWidth;
private int mMenuRightPadding;
private int mMenuWidth;
private boolean hasMeasured = false;
private boolean isOpen = false;
public SlidingMenuView(Context context) {
this(context, null);
}
public SlidingMenuView(Context context, AttributeSet attrs) {
this(context, attrs, -1);
}
/**
* 当使用了 自定义属性时, 会调用 此构造方法
*/
public SlidingMenuView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// 获取自定义的属性
TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
R.styleable.SlidingMenu, defStyle, 0);
mMenuRightPadding = a.getDimensionPixelSize(a.getIndex(0),
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
100, context.getResources().getDisplayMetrics()));
a.recycle();
WindowManager wm = (WindowManager) context
.getSystemService(context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
mScreenWidth = outMetrics.widthPixels;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (hasMeasured == false) {
mWapper = (LinearLayout) getChildAt(0);
mMenu = (ViewGroup) mWapper.getChildAt(0);
mContent = (ViewGroup) mWapper.getChildAt(1);
mMenuWidth = mMenu.getLayoutParams().width = mScreenWidth
- mMenuRightPadding;
mContent.getLayoutParams().width = mScreenWidth;
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if (changed)
this.scrollTo(mMenuWidth, 0);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_UP:
int scrollX = getScrollX(); // 隐藏 在 左边 的 宽度
if (scrollX >= mMenuWidth / 2) {
this.smoothScrollTo(mMenuWidth, 0);
isOpen = false;
} else {
this.smoothScrollTo(0, 0);
isOpen = true;
}
return true;
default:
break;
}
return super.onTouchEvent(ev);
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
// 手指滑动时, l 的 值 是 从 mMenuWidth 到 0
Log.e("onScrollChanged", "l="+l + " , oldl="+oldl+ ", mMenuWidth =" +mMenuWidth);
float scaleX = l * 1.0f / mMenuWidth ; // 1.0 ~ 0.0
float contentScale = 0.7f+scaleX*0.3f;
float menuScale = 0.6f + 0.4f *(1- scaleX);
ViewHelper.setTranslationX(mMenu, mMenuWidth * scaleX * 0.95f);
ViewHelper.setPivotX(mMenu, 0);
ViewHelper.setPivotY(mMenu, mContent.getHeight()/2);
ViewHelper.setScaleX(mMenu, menuScale);
ViewHelper.setScaleY(mMenu, menuScale);
ViewHelper.setPivotX(mContent, 0);
ViewHelper.setPivotY(mContent, mContent.getHeight()/2);
ViewHelper.setScaleX(mContent, contentScale);
ViewHelper.setScaleY(mContent, contentScale);
}
public void open() {
if (isOpen == true) {
return;
} else {
this.smoothScrollTo(0, 0);
isOpen = true;
}
}
public void close() {
if (isOpen == true) {
this.smoothScrollTo(mMenuWidth, 0);
isOpen = false;
} else {
return;
}
}
public void toggle(){
if( isOpen )
close();
else
open();
}
}
2、 xml布局文件中使用的方法如下, 注意 HorizontalScrollView 的子布局里只允许有一个根View
<com.example.slidingmenu.SlidingMenuView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent" >
<include layout="@layout/sliding_menu" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#f0f"
android:gravity="center" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="内容页" />
</LinearLayout>
</LinearLayout>
</com.example.slidingmenu.SlidingMenuView>
3、运行效果图
4、 总结
准备知识:
a. 四舍五入的代码就是把结果加上0.5f再进行强制转换
b. getDimension()是基于当前DisplayMetrics进行转换,获取指定资源id对应的尺寸。文档里并没说这里返回的就是像素,要注意这个函数的返回值是float,像素肯定是int。
getDimensionPixelSize()与getDimension()功能类似,不同的是将结果转换为int,并且小数部分四舍五入。
getDimensionPixelOffset()与getDimension()功能类似,不同的是将结果转换为int,并且偏移转换(offset conversion,函数命名中的offset是这个意思)是直接截断小数位,即取整(其实就是把float强制转化为int,注意不是四舍五入哦)。
1、SlidingMenuView 类的实现如下,
package com.example.slidingmenu;
import com.nineoldandroids.view.ViewHelper;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
public class SlidingMenuView extends HorizontalScrollView {
/*
* 1、书写自定义属性的 attr.xml 属性 </br> 2、使用时引入 xmlns命名空间 3、在构造方法中获得我们设置的值
*/
private LinearLayout mWapper;
private ViewGroup mMenu;
private ViewGroup mContent;
private int mScreenWidth;
private int mMenuRightPadding;
private int mMenuWidth;
private boolean hasMeasured = false;
private boolean isOpen = false;
public SlidingMenuView(Context context) {
this(context, null);
}
public SlidingMenuView(Context context, AttributeSet attrs) {
this(context, attrs, -1);
}
/**
* 当使用了 自定义属性时, 会调用 此构造方法
*/
public SlidingMenuView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// 获取自定义的属性
TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
R.styleable.SlidingMenu, defStyle, 0);
mMenuRightPadding = a.getDimensionPixelSize(a.getIndex(0),
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
100, context.getResources().getDisplayMetrics()));
a.recycle();
WindowManager wm = (WindowManager) context
.getSystemService(context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
mScreenWidth = outMetrics.widthPixels;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (hasMeasured == false) {
mWapper = (LinearLayout) getChildAt(0);
mMenu = (ViewGroup) mWapper.getChildAt(0);
mContent = (ViewGroup) mWapper.getChildAt(1);
mMenuWidth = mMenu.getLayoutParams().width = mScreenWidth
- mMenuRightPadding;
mContent.getLayoutParams().width = mScreenWidth;
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if (changed)
this.scrollTo(mMenuWidth, 0);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_UP:
int scrollX = getScrollX(); // 隐藏 在 左边 的 宽度
if (scrollX >= mMenuWidth / 2) {
this.smoothScrollTo(mMenuWidth, 0);
isOpen = false;
} else {
this.smoothScrollTo(0, 0);
isOpen = true;
}
return true;
default:
break;
}
return super.onTouchEvent(ev);
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
// 手指滑动时, l 的 值 是 从 mMenuWidth 到 0
Log.e("onScrollChanged", "l="+l + " , oldl="+oldl+ ", mMenuWidth =" +mMenuWidth);
float scaleX = l * 1.0f / mMenuWidth ; // 1.0 ~ 0.0
float contentScale = 0.7f+scaleX*0.3f;
float menuScale = 0.6f + 0.4f *(1- scaleX);
ViewHelper.setTranslationX(mMenu, mMenuWidth * scaleX * 0.95f);
ViewHelper.setPivotX(mMenu, 0);
ViewHelper.setPivotY(mMenu, mContent.getHeight()/2);
ViewHelper.setScaleX(mMenu, menuScale);
ViewHelper.setScaleY(mMenu, menuScale);
ViewHelper.setPivotX(mContent, 0);
ViewHelper.setPivotY(mContent, mContent.getHeight()/2);
ViewHelper.setScaleX(mContent, contentScale);
ViewHelper.setScaleY(mContent, contentScale);
}
public void open() {
if (isOpen == true) {
return;
} else {
this.smoothScrollTo(0, 0);
isOpen = true;
}
}
public void close() {
if (isOpen == true) {
this.smoothScrollTo(mMenuWidth, 0);
isOpen = false;
} else {
return;
}
}
public void toggle(){
if( isOpen )
close();
else
open();
}
}
2、 xml布局文件中使用的方法如下, 注意 HorizontalScrollView 的子布局里只允许有一个根View
<com.example.slidingmenu.SlidingMenuView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent" >
<include layout="@layout/sliding_menu" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#f0f"
android:gravity="center" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="内容页" />
</LinearLayout>
</LinearLayout>
</com.example.slidingmenu.SlidingMenuView>
3、运行效果图
4、 总结
相关文章推荐
- 使用HorizontalScrollView实现最简单的侧滑菜单
- Android学习笔记 :自定义HorizontalScrollView实现侧滑菜单
- 使用HorizontalScrollView实现侧滑效果(3)
- android:自定义HorizontalScrollView实现qq侧滑菜单 标签: HorizontalScrollView自定义viewqq侧滑菜单 2016
- android:自定义HorizontalScrollView实现qq侧滑菜单
- 自定义 view 练习(1):用 HorizontalScrollView 实现自定义侧滑菜单
- 仿QQ侧滑菜单,HorizontalScrollView和DrawerLayout实现对比
- 使用HorizontalScrollView实现侧滑ListView
- 利用HorizontalScrollView实现侧滑菜单
- SlidingMenu重写HorizontalScrollView实现菜单侧滑的效果
- 使用HorizontalScrollView实现侧滑效果(1)
- 使用HorizontalScrollView实现侧滑效果(2)
- 利用HorizontalScrollView实现仿QQ的侧滑菜单
- 使用HorizontalScrollView简单实现柱状图
- 使用HorizontalScrollView实现水平控件拖动效果
- HorizontalScrollView 使用 实现textview和viewpager的联动
- 使用 HorizontalScrollView 实现滚动控制
- Android 使用HorizontalScrollView 实现图片画廊
- 51.使用HorizontalScrollView+LinearLayout实现文字+图片的自动跑马灯效果
- Android 使用HorizontalScrollView 实现Gallery效果