侧滑菜单——方式一(继承自HorizontalScrollVie
这是最简单的侧滑菜单方式了
只需要重写onMeasure()、onLayout()和onTouchEvnet()方法即可;
ViewGroup的自定义属性
<declare-styleable name="SlidingMenu">
<attr name="rightMargin" format="dimension"/>
</declare-styleable>```
####自定义ViewGroup
public class SlidingMenu extends HorizontalScrollView {
private LinearLayout mLinearLayout;//scrollview内嵌的唯一布局,linearlayout
private ViewGroup mMenu, mContent;//菜单,内容的布局
private int mScreenWidth;//屏幕宽度
//dp
private int mMenuRightMargin ;//菜单距离屏幕的右边距
//为了防止onMeasure调用多次
private boolean once;
public SlidingMenu(Context context) {
this(context,null);
}
public SlidingMenu(Context context, AttributeSet attrs) {
this(context,attrs,0);
}
public SlidingMenu(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
WindowManager windowManager =
(WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(outMetrics);
mScreenWidth = outMetrics.widthPixels;
TypedArray ta =
context.obtainStyledAttributes(attrs, R.styleable.SlidingMenu);
mMenuRightMargin= (int) ta.getDimension(R.styleable.SlidingMenu_rightMargin,TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics())); //把dp转化为px
ta.recycle();//回收,以防泄漏
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (!once) {
mLinearLayout = (LinearLayout) this.getChildAt(0);//scrollView的唯一子View
mMenu = (ViewGroup) mLinearLayout.getChildAt(0);
mContent = (ViewGroup) mLinearLayout.getChildAt(1);
//测量menu的宽和内容区域的宽
mMenu.getLayoutParams().width = mScreenWidth - mMenuRightMargin;
mContent.getLayoutParams().width = mScreenWidth;
once = true;
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
/*
* 设置偏移量将menu隐藏
*/
@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(mMenu.getMeasuredWidth(), 0);
}
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
//无需重写这个case,scrollview自带scroller辅助类,会自动滑出来,这也是这样实现侧滑菜单的方便之处
break;
case MotionEvent.ACTION_UP:
if(getScrollX()>mMenu.getMeasuredWidth()/2){//菜单未滑出一半
this.smoothScrollTo(mMenu.getMeasuredWidth(),0);//平滑移动,带动画
slidemenu.gif
}else{
this.smoothScrollTo(0,0);
}
return true;
}
return super.onTouchEvent(ev);
}
}```
写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"
android:background="@color/colorAccent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/img1"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerVertical="true"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:src="@mipmap/ic_launcher" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textColor="#ffffff"
android:text="第1个item"
android:layout_toRightOf="@id/img1"
android:layout_centerVertical="true"/>
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/img2"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerVertical="true"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:src="@mipmap/ic_launcher" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textColor="#ffffff"
android:text="第2个item"
android:layout_toRightOf="@id/img2"
android:layout_centerVertical="true"/>
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/img3"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerVertical="true"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:src="@mipmap/ic_launcher" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textColor="#ffffff"
android:text="第3个item"
android:layout_toRightOf="@id/img3"
android:layout_centerVertical="true"/>
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/img4"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerVertical="true"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:src="@mipmap/ic_launcher" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textColor="#ffffff"
android:text="第4个item"
android:layout_toRightOf="@id/img4"
android:layout_centerVertical="true"/>
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/img5"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerVertical="true"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:src="@mipmap/ic_launcher" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textColor="#ffffff"
android:text="第5个item"
android:layout_toRightOf="@id/img5"
android:layout_centerVertical="true"/>
</RelativeLayout>
</LinearLayout>
</RelativeLayout>```
效果如下
![menu.png](http:https://img.haomeiwen.com/i1814117/2941b09de4dc9381.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
####接着写主布局文件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="mahjongmachine.scrollerdemo.MainActivity">
<com.scrollerdemo.SlidingMenu
xmlns:app="http://schemas.android.com/apk/res-auto"
app:rightMargin="100dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorAccent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/menu"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimary">
</LinearLayout>
</LinearLayout>
</com.scrollerdemo.SlidingMenu>
</RelativeLayout>```
最终效果如下
slidemenu.gif在此基础上还可以优化成为抽屉式的侧滑菜单
效果图如下
slide.gif这个的原理在于使用属性动画使得menu页面在整个scrollview滑动的过程,不断的往右偏移,从一开始的需要偏移整个menu的宽度,到逐渐的变小为0.
在原来代码的基础上加上onScrollChanged,ViewHelper使用的是开源的动画工具nineoldandroids
//l为当前屏幕的左边界处于的scrollview的x轴上的位置
//t为当前屏幕的上边界处于的scrollview的y轴上的位置,一般在垂直方向scrollView上
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
float scale=l*1.0f/mMenu.getWidth();//1~ 0
//调用属性动画,设置translationX
ViewHelper.setTranslationX(mMenu,mMenu.getWidth()*scale);//一开始偏移整个宽
}```
####继续进阶,模仿QQ侧滑菜单
其实很简单,给content区域增加scale动画,给menu添加scale和alpha动画
改写onScrollChanged方法
代码如下
/**
* QQ侧滑菜单
* 区别:
* 内容区域1.0-0.7缩放 0.7+scale0.3
* 菜单的偏移量不同
* 菜单显示时有缩放和透明度变化 缩放0.7-1.0 1.0-scale0.3 透明度0.6-1.0 1.0-scale*0.4
*/
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
float scale = l * 1.0f / mMenu.getWidth();//1~ 0
float contentScale = 0.8f + scale * 0.3f;
float menuScale = 1f - scale * 0.3f;
float menuAlpha = 1f - scale * 0.4f;
//调用属性动画,设置translationX
ViewHelper.setTranslationX(mMenu, mMenu.getWidth() * scale * 0.7f);//一开始偏移0.7*宽,还有0.3部分在外面
ViewHelper.setAlpha(mMenu, menuAlpha);
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);
}```
效果图如下
slidemenu.gif