自定义View系列android成神之路Android

侧滑菜单——方式一(继承自HorizontalScrollVie

2016-10-10  本文已影响871人  JC_Hou

这是最简单的侧滑菜单方式了
只需要重写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-scale
0.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
上一篇下一篇

猜你喜欢

热点阅读