您的位置:首页 > 其它

仿QQ5.0侧滑菜单实现

2015-08-23 17:18 381 查看
周末两天时间在公司里研究新版QQ的侧滑菜单的实现,在网上也看到一些实例,也看了慕课网上的课程,终于完全搞明白了整个实现过程,现将我的理解和实现写出来。

自定义控件--显示侧滑菜单和内容的horizontalScrollView

需要用到 HorizontalScrollView控件,同时要实现

(1)初始状态是显示内容,隐藏菜单

(2)当滑动超过屏幕一般的响应。(隐藏菜单or显示菜单)

(3)滑动过程中内容区域的缩放,菜单的偏移和缩放以及透明度变化。

(4)点击按钮,切换菜单的显示和隐藏

(1)初始状态是显示内容,隐藏菜单

 第一步:重写了自定义控件的两个参数的构造方法,主要目的是得到屏幕宽度和菜单的右边距
//未定义属性时使用
public SlidingMenu(Context context, AttributeSet attrs) {
super(context, attrs);

//        //获取屏幕宽度
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
mScreenWidth = outMetrics.widthPixels;

//menu右边距,转化为像素值
mMenuRight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics());
//        this(context, attrs, 0);
}
第二步:重写onMeasure(),决定菜单区域和内容区域的宽高,这样自定义视图的宽高就决定了
<pre name="code" class="html">//重写onMeasure(),决定内部子view的宽高,并决定该控件的宽高

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (!once) {
//获取LinearLayout
mWapper = (LinearLayout) getChildAt(0);
//获取菜单和内容
mMenu = (ViewGroup) mWapper.getChildAt(0);
mContent = (ViewGroup) mWapper.getChildAt(1);

//设置菜单和内容的宽高
mMenu.getLayoutParams().width = mScreenWidth - mMenuRight;
mMenuWidth = mScreenWidth - mMenuRight;
mContent.getLayoutParams().width = mScreenWidth;

//决定子view视图的宽高后该视图的宽高就决定了,无需再设定
once = true;
}

}
第三步:重写onLayout()方法,决定控件的布局,即初始状态只显示内容区域隐藏菜单区域
//重写onLayout(),决定视图的位置
@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);
}

}
这里使用到scrollTo()方法,设置scrollView的偏移,实现隐藏菜单。

第四步:重写OnTouchEvent()方法,实现滑动之后如果菜单显示超过屏幕一般则全部显示,否则隐藏

//重写TouchEvent(),监听手抬起时的动作
@Override
public boolean onTouchEvent(MotionEvent ev) {

int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_UP: {

//判断此时scrollview滚动的距离与menu宽度比较,如果大于一般则隐藏,如果小于一半则显示
int scrollX = this.getScrollX();
int helfMenuWidth = mMenuWidth / 2;
if (scrollX >= helfMenuWidth) {
//隐藏menu
this.smoothScrollTo(mMenuWidth, 0);
isOpen = false;
} else {
//显示menu
this.smoothScrollTo(0, 0);
isOpen = true;
}
return true;
}

}
return super.onTouchEvent(ev);
}

这样基本的功能已经实现,再添加上按钮实现

(2)点击按钮,菜单显示隐藏的切换

第一步:按钮设置监听事件
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

//切换菜单
slideMenu.changeMenu();

}
});
第二步:实现切换:
public void changeMenu() {
if(isOpen){//如果是开启则关闭
closeMenu();
}else{
openMenu();
}

}

//打开菜单,设置标志
private void openMenu() {
this.smoothScrollTo(0,0);
isOpen = true;
}

//关闭菜单,设置标志
private void closeMenu() {
this.smoothScrollTo(mMenuWidth,0);
isOpen = false;
}
菜单的显示隐藏就是使用的scrollView的smoothSrollTo()这样的函数,让滑动更加平滑。切换是定义了一个标志,状态改变时修改标志,同时注意要在onTouchEvent()中显示隐藏也要修改标志。

(3)实现自定义属性

<com.example.chengyajun.slidingmenu.view.SlidingMenu
android:id="@+id/slidemenu"
android:layout_width="match_parent"
test:rightPadding="80dp"
android:layout_height="match_parent">

如何实现在xml布局文件中动态修改菜单的右边距呢?test:rightPadding="80dp" 第一步:values文件夹下创建attr.xml文件,设置属性的基本信息
<?xml version="1.0" encoding="utf-8"?>
<resources>

<attr name="rightPadding" format="dimension"></attr>

<declare-styleable name="SlidingMenu">
<attr name="rightPadding"></attr>
</declare-styleable>

</resources>

第二步:布局文件中,声明xmlns,在eclipse和andr
4000
oid studio中优点不一样,实现的时候要注意一下。eclipse : xmlns:test="http://schemas.android.com/apk/res/com.example.chengyajun.slidingmenu"android studio : xmlns:test="http://schemas.android.com/apk/res-auto"第三步:重写自定义视图的构造方法,获取自定义属性的值
//一个参数的构造方法,代码中只用new来创建对象
public SlidingMenu(Context context) {
//        super(context);
this(context, null);
}

//未定义属性时使用
public SlidingMenu(Context context, AttributeSet attrs) {
//        super(context, attrs);

//        //获取屏幕宽度
//        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
//        DisplayMetrics outMetrics = new DisplayMetrics();
//        wm.getDefaultDisplay().getMetrics(outMetrics);
//        mScreenWidth = outMetrics.widthPixels;
//
//        //menu右边距,转化为像素值
//        mMenuRight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics());
this(context, attrs, 0);
}

//三个参数的构造方法,使用了自动以属性
public SlidingMenu(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);

//对右边距进行设置

// 获取我们定义的属性
TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
R.styleable.SlidingMenu, defStyleAttr, 0);

int n = a.getIndexCount();
for (int i = 0; i < n; i++) {
int attr = a.getIndex(i);
switch (attr) {
case R.styleable.SlidingMenu_rightPadding:
mMenuRight = a.getDimensionPixelSize(attr,
(int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 50, context
.getResources().getDisplayMetrics()));
break;
}
}
a.recycle();

//获取屏幕宽度
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
mScreenWidth = outMetrics.widthPixels;

}
分别重写一个参数,两个参数,三个参数的构造方法,一个参数:new一个对象时候两个参数:没有自定义控件三个参数:使用了自定义控件注意:自定义属性值得获取,需要及时的释放资源。
(4)实现属性动画:内容区域的缩放,菜单的偏移、缩放和透明度变化此时需要引入一个jar包 :nineoldandroids-2.4.0.jar,android3.0以下的需要这个jar包需要重写scrollView的onScrollChanged(),在滑动过程中实现动画效果
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {//l=getScrollX()
float scale = l*1.0f/mMenuWidth;   //隐藏的比例1.0~0

//抽屉菜单的实现,菜单在拉动过程中偏移
//当滑动过程中,移动menu,menu的偏移
//        ViewHelper.setTranslationX(mMenu,l);//隐藏多少,就让menu偏移多少,这样保证menu的x起点始终在屏幕x起点

//QQ菜单实现
/**
* 内容区域的缩放:1.0~0.7   0.7+0.3*scale
* 菜单区域的缩放:0.7~1.0    1.0-0.3*scale
* 菜单区域的透明度:0.7~1.0  1.0-0.3*scale
*
*/

//内容区域   缩放
ViewHelper.setScaleX(mContent,0.7f+0.3f*scale);
ViewHelper.setScaleY(mContent,0.7f+0.3f*scale);
//移动到最后发现全部隐藏了,因为当到达最后的80dp后,区域缩放且默认缩放点在中心,导致看不见
//修改区域的缩放点
ViewHelper.setPivotX(mContent,0);
ViewHelper.setPivotY(mContent,mContent.getHeight()/2);

//菜单区域

//偏移
ViewHelper.setTranslationX(mMenu,l*0.8f);

//        //缩放
ViewHelper.setScaleX(mMenu, 1.0f-0.3f*scale);
ViewHelper.setScaleY(mMenu,1.0f-0.3f*scale);

//透明度
ViewHelper.setAlpha(mMenu,1.0f-0.3f*scale);

}
通过ViewHelper来实现动画,缩放的比例控制需要根据scrollView的滑动比例来决定。在实现过程中开始没有修改内容区域的缩放中心点,发现直接隐藏了,后面才知道原来到最后的80dp后,区域还要缩放,而且默认缩放中心点在区域中心,这样就看不见了,后来修改区域缩放的中心点未左边中间点,这样就是到最后也是停留在80dp的位置。这样整个自定义的视图就写完了,技术难点也解释了。

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息