Android自定义ViewGroup打造各种风格的SlidingMenu
看鸿洋大大的QQ5.0侧滑菜单的视频课程,对于侧滑的时的动画效果的实现有了新的认识,似乎打通了任督二脉,目前可以实现任意效果的侧滑菜单了,感谢鸿洋大大!!
鸿洋大大用的是HorizontalScrollView来实现的侧滑菜单功能,HorizontalScrollView的好处是为我们解决了滑动功能,处理了滑动冲突问题,让我们使用起来非常方便,但是滑动和冲突处理都是android中的难点,是我们应该掌握的知识点,掌握了这些,我们可以不依赖于系统的API,随心所欲打造我们想要的效果,因此这篇文章我将直接自定义ViewGroup来实现侧滑菜单功能
首先我们先来看一看效果图,第一个效果图是一个最普通的侧滑菜单,我们一会儿会先做出这种侧滑菜单,然后再在此基础上实现另外两个效果
第一种
第二种
第三种
实现第一种侧滑菜单,继承自ViewGroup
继承自ViewGroup需要我们自己来测量,布局,实现滑动的效果,处理滑动冲突,这些都是一些新手无从下手的知识点,希望看了这篇文章后可以对大家有一个帮助
自定义ViewGroup的一般思路是重写onMeasure方法,在onMeasure方法中调用measureChild来测量子View,然后调用setMeasuredDimension来测量自己的大小。然后重写onLayout方法,在onLayout中调用子View的layout方法来确定子View的位置,下面我们先来做好这两件工作
初始时候我们的Content应该是显示在屏幕中的,而Menu应该是显示在屏幕外的。当Menu打开时,应该是这种样子的
mMenuRightPadding是Menu距屏幕右侧的一个距离,因为我们Menu打开后,Content还是会留一部分,而不是完全隐藏的
public class MySlidingMenu extends ViewGroup {
public MySlidingMenu(Context context) {
this(context, null, 0);
}
public MySlidingMenu(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MySlidingMenu(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
DisplayMetrics metrics = new DisplayMetrics();
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
wm.getDefaultDisplay().getMetrics(metrics);
//获取屏幕的宽和高
mScreenWidth = metrics.widthPixels;
mScreenHeight = metrics.heightPixels;
//设置Menu距离屏幕右侧的距离,convertToDp是将代码中的100转换成100dp
mMenuRightPadding = convertToDp(context,100);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//拿到Menu,Menu是第0个孩子
mMenu = (ViewGroup) getChildAt(0);
//拿到Content,Content是第1个孩子
mContent = (ViewGroup) getChildAt(1);
//设置Menu的宽为屏幕的宽度减去Menu距离屏幕右侧的距离
mMenuWidth = mMenu.getLayoutParams().width = mScreenWidth - mMenuRightPadding;
//设置Content的宽为屏幕的宽度
mContentWidth = mContent.getLayoutParams().width = mScreenWidth;
//测量Menu
measureChild(mMenu,widthMeasureSpec,heightMeasureSpec);
//测量Content
measureChild(mContent, widthMeasureSpec, heightMeasureSpec);
//测量自己,自己的宽度为Menu宽度加上Content宽度,高度为屏幕高度
setMeasuredDimension(mMenuWidth + mContentWidth, mScreenHeight);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
//摆放Menu的位置,根据上面图可以确定上下左右的坐标
mMenu.layout(-mMenuWidth, 0, 0, mScreenHeight);
//摆放Content的位置
mContent.layout(0, 0, mScreenWidth, mScreenHeight);
}
/**
* 将传进来的数转化为dp
*/
private int convertToDp(Context context , int num){
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,num,context.getResources().getDisplayMetrics());
}
}
目前我们的侧滑菜单中的两个子View的位置应该是这个样子
接下来我们编写xml布局文件
left_menu.xml 左侧菜单的布局文件,是一个ListView
其中ListView的Item布局为left_menu_item.xml
<code class=" hljs xml"><!--{cke_protected}{C}%3C!%2D%2D%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%2D%2D%3E--> <linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:gravity="center_vertical" android:layout_height="match_parent"> <imageview android:id="@+id/menu_imageview" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/menu_1" android:padding="20dp"> <textview android:id="@+id/menu_textview" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="菜单1" android:textcolor="#000000" android:textsize="20sp"> </textview></imageview></linearlayout></code>
我们再来编写内容区域的布局文件 content.xml 其中有一个header,header中有一个ImageView,这个ImageView是menu的开关,我们点击他的时候可以自动开关menu,然后header下面也是一个listview
<code class=" hljs xml"><!--{cke_protected}{C}%3C!%2D%2D%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%2D%2D%3E--> <linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <linearlayout android:layout_width="match_parent" android:layout_height="65dp" android:background="#000000" android:gravity="center_vertical" android:orientation="horizontal"> <imageview android:id="@+id/menu_toggle" android:layout_width="40dp" android:layout_height="40dp" android:src="@drawable/toggle" android:paddingleft="10dp"> </imageview></linearlayout> <listview android:id="@+id/content_listview" android:layout_width="match_parent" android:layout_height="wrap_content" android:dividerheight="0dp" android:divider="@null" android:scrollbars="none"> </listview></linearlayout></code>
content的item的布局文件为 content_item.xml
<code class=" hljs xml"><!--{cke_protected}{C}%3C!%2D%2D%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%2D%2D%3E--> <linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:gravity="center_vertical" android:background="#ffffff" android:layout_height="match_parent"> <imageview android:id="@+id/content_imageview" android:layout_width="80dp" android:layout_height="80dp" android:src="@drawable/content