在慕课网上看了鸿洋扣扣5.0菜单的视频,在这里写下新的也顺便梳理一下里面涉及到的知识点。不得不佩服大神的深度,讲的非常好。
一、普通侧滑菜单的实
定义出menu的布局文件。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:orientation="vertical">
<-- 里面随意放一些组件来显示一下 -->
</LinearLayout>
</RelativeLayout>
主布局代码
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:costunattr="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/img_frame_background"
tools:context="com.herodemo.sheadon.qq50_slide_menu.MainActivity">
<!--HorizontalScrollView内部只能有一个控件-->
<com.herodemo.sheadon.qq50_slide_menu.view.SlidingMenu
android:id="@+id/sliding_menu"
costunattr:rightPadding="80dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal">
<-- 上面定义的menu菜单-->
<include layout="@layout/left_menu"/
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@drawable/qq"
</LinearLayout>
</LinearLayout> </com.herodemo.sheadon.qq50_slide_menu.view.SlidingMenu>
</RelativeLayout>
自定义一个SlidingMenu,让它继承HorizontalScrollView,因为HorizontalScrollView可以自动处理水平的滑动事件,这样我们就不必人工处理ACTION_MOVE事件了。
public class SlidingMenu extends HorizontalScrollView
覆盖两个参数的构造方法该构造方法会在加载布局文件时调用,前提是没有自定义布局属性。
public SlidingMenu(Context context, AttributeSet attrs){
//得到系统的宽度像素
WindowManager wm = (WindowManager) context.
getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics metrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(metrics);
this.mSreenWidth = metrics.widthPixels;//得到宽度像素值
}
重写onMeasure()方法确定view的宽高
/**
* 设置子view的宽和高
* 设置自己的宽和高
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if(once == false){
mWapper = (LinearLayout) getChildAt(0);
mMenu = (ViewGroup) mWapper.getChildAt(0);
mContent = (ViewGroup) mWapper.getChildAt(1);
mMenuWidth = mMenu.getLayoutParams().width = mSreenWidth - mMenuRightPadding;
mContent.getLayoutParams().width = mSreenWidth;
//menu和content都设置好之后mWraper会自己设置宽度
once = true;
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
这里有一个非常重要的东西需要理解:
在我刚开始实现的时候遇到一个问题,就是运行该布局后menu和content内容都在一个屏幕上面。而在布局文件中无论怎样修该布局参数都起不到作用。
这里一个关键的问题就是,你要在onMeasure的方法中指定menu和content的长宽,如果不做特别指定,系统会默认在一个屏幕下显示两个布局文件。在上面的方法中,特别指定了menu的宽度为屏幕宽度,mContent的宽度也是屏幕的宽度,这样HorizontalScrollView类的水平滑动效果就会起作用了。
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
//判断当前布局改变le
if(changed){
//布局文件加载后,立即滑动只让content部分显示在屏幕上
//所以,必须在super.onLayout()中加载
this.scrollTo(mMenuWidth, 0);
}
}
接下来就是控制滑动事件了,因为继承了水平滑动布局,所以ACTION_MOVE时间就不用我们亲自处理了,省下了很多麻烦。我们只需要处理ACTION_UP事件。
case MotionEvent.ACTION_UP:
//隐藏在左边的宽度,并不是显示的宽度
int scrollX = getScrollX();
if (scrollX <= mMenuWidth/2){
//打开菜单
smoothScrollTo(0,0);
isOpen = true;
}else{
smoothScrollTo(mMenuWidth,0);
isOpen = false;
}
return true;
完成了这些,一个具有基本功能的滑动菜单试图就完成了。
接下来,要做一些动画的处理,实现缩放,透明度,位移的一些变化
View 类有一个方法叫做 onScrollChanged(int l, int t, int oldl, int oldt),当view在滚动时就会不停的回调该方法,其中参数l就是当前view在屏幕边缘的地方在该view中的left值,放menu被完全遮盖时,left值为menu的宽度,当menu完全显示时,left值为0。
我们就可以利用这一点,将l值转化成一个从1~0的梯度值。
float scale = l* 1.0f/mMenuWidth;
1、实现偏移量的变化:
首先,我们要认识一个变量,translationX,它代表view与父view之间的横坐标偏移值。
看下效果: