Android自定义侧滑菜单

?现在android中有很多产品实现了侧边栏菜单的滑动,比如说百度贴吧、腾讯QQ、Facebook、知乎等,这样做的好处:

一是可以装下更多的内容,二是给用户更好的视觉感受。

?

?下面举一个知乎的例子:

?

一、实现的思路:

首先定义三个FrameLayout:leftMenu、middleMenu、rightMenu

middleMenu为主面板,大小设置为屏幕的大小;

leftMenu、rightMenu为左右侧边栏,大小设置为屏幕的一定比例,我设置的是80%,位置分别设置在middleMenu的左右两边,一开始打开的时候并不能看见。

?

实现的滑动的方法是dispatchTouchEvent() :

通过ACTION_DOWN和ACTION_MOVE不断获取滑动中的x、y坐标来进行判断是上下滑动还是左右滑动,通过Scroller来实现滑动的动画效果。

?

二、代码:?

import android.content.Context;
import android.graphics.Color;
import android.graphics.Point;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
import android.widget.Scroller;
public class MainUI extends RelativeLayout {
    private Context context;
    private FrameLayout leftMenu;//设置左面板
    private FrameLayout middleMenu;//设置主面板
    private FrameLayout rightMenu;//设置右面板
    private Scroller mScroller;
    private FrameLayout middleMask;

    public static final int LEFT_ID = 0xaabbcc;
    public static final int MIDDLE_ID = 0xaaccbb;
    public static final int RIGHT_ID = 0xccbbaa;

    public MainUI(Context context) {
        super(context);
        initView(context);
    }

    public MainUI(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView(context);
    }

    private void initView(Context context) {//初始化
        this.context = context;
        mScroller = new Scroller(context, new DecelerateInterpolator());
        leftMenu = new FrameLayout(context);
        middleMenu = new FrameLayout(context);
        rightMenu = new FrameLayout(context);
        middleMask = new FrameLayout(context);
        leftMenu.setBackgroundColor(Color.RED);
        middleMenu.setBackgroundColor(Color.GREEN);
        rightMenu.setBackgroundColor(Color.RED);
        leftMenu.setId(LEFT_ID);
        middleMenu.setId(MIDDLE_ID );
        rightMenu.setId(RIGHT_ID );
        middleMask.setBackgroundColor(0x88000000);
        addView(leftMenu);
        addView(middleMenu);
        addView(rightMenu);
        addView(middleMask);
        middleMask.setAlpha(0);//设置透明度
    }
    public float onMiddleMask(){
        System.out.println("透明度:"+middleMask.getAlpha());
        return middleMask.getAlpha();
    }
    public void scrollTo(int x,int y){//滑动方法
        super.scrollTo(x,y);
        onMiddleMask();
        int curX = Math.abs(getScrollX());
        float scale = curX/(float)leftMenu.getMeasuredWidth();
        middleMask.setAlpha(scale);
    }

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {//设置面板大小
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        middleMenu.measure(widthMeasureSpec, heightMeasureSpec);
        middleMask.measure(widthMeasureSpec, heightMeasureSpec);
        int realWidth = MeasureSpec.getSize(widthMeasureSpec);
        int tempWidthMeasure = MeasureSpec.makeMeasureSpec((int) (realWidth * 0.8f), MeasureSpec.EXACTLY);
        leftMenu.measure(tempWidthMeasure, heightMeasureSpec);
        rightMenu.measure(tempWidthMeasure, heightMeasureSpec);
    }

    protected void onLayout(boolean changed, int l, int t, int r, int b) {//设置面板位置
        super.onLayout(changed, l, t, r, b);
        middleMenu.layout(l, t, r, b);
        middleMask.layout(l, t, r, b);
        leftMenu.layout(l - leftMenu.getMeasuredWidth(), t, l, b);
        rightMenu.layout(l + middleMenu.getMeasuredWidth(), t,
                r + rightMenu.getMeasuredWidth(), b);
    }

    private boolean isTestCompete;
    private boolean isleftrightEvent;

    public boolean dispatchTouchEvent(MotionEvent ev) {//事件分发
        if (!isTestCompete) {
            getEventType(ev);
            return true;
        }
        if (isleftrightEvent) {//如果是左右滑动
            switch (ev.getActionMasked()) {
                case MotionEvent.ACTION_MOVE:
                    int curScrollX = getScrollX();//滚动距离
                    int dis_x = (int) (ev.getX() - point.x);//手指按下后滑动距离
                    int expectX = -dis_x + curScrollX;
                    int finalX = 0; //初始化屏幕滑动距离
                    if (expectX < 0) { //向左滑动
                        finalX = Math.max(expectX, -leftMenu.getMeasuredWidth());
                    } else { //向右滑动
                        finalX = Math.min(expectX, rightMenu.getMeasuredWidth());
                    }

                    scrollTo(finalX, 0);//屏幕移动
                    point.x = (int) ev.getX();
                    break;
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL:
                    curScrollX = getScrollX();
                    if (Math.abs(curScrollX) > leftMenu.getMeasuredWidth() >> 1) {//滑动大于屏幕距离一半时,启动动画
                        if (curScrollX < 0) {//向左
                            mScroller.startScroll(curScrollX, 0, -leftMenu.getMeasuredWidth() - curScrollX, 0);
                        } else {//向右
                            mScroller.startScroll(curScrollX, 0, leftMenu.getMeasuredWidth() - curScrollX, 0);
                        }
                    } else {
                        mScroller.startScroll(curScrollX, 0, -curScrollX, 0);//距离不到返回原点

                    }
                    invalidate();//View重绘
                    isleftrightEvent = false;
                    isTestCompete = false;
                    break;
            }
        } else {//上下滑动也要初始化
            switch (ev.getActionMasked()) {
                case MotionEvent.ACTION_UP:
                    isleftrightEvent = false;
                    isTestCompete = false;
                    break;
            }
        }
        return super.dispatchTouchEvent(ev);
    }

    private Point point = new Point();
    private static  final int TEST_DIS = 20;
    public void computeScroll() {//回调方法
        super.computeScroll();
        if (!mScroller.computeScrollOffset()) {
            return;
        }
        int tempX = mScroller.getCurrX();//总滑动值
        scrollTo(tempX, 0);
    }

    private void getEventType(MotionEvent e) {//判断事件类型
        switch (e.getActionMasked()){
            case MotionEvent.ACTION_DOWN:
                point.x=(int) e.getX();
                point.y=(int) e.getY();
                super.dispatchTouchEvent(e);
                break;
            case MotionEvent.ACTION_MOVE:
                int dX = Math.abs((int) e.getX()-point.x);
                int dY = Math.abs((int) e.getY()-point.y);
                if(dX > TEST_DIS && dX > dY){//左右滑动
                    isleftrightEvent = true;
                    isTestCompete = true;
                    point.x = (int)e.getX();
                    point.y = (int)e.getY();
                }else if(dY > TEST_DIS && dY>dX){//上下滑动
                    isleftrightEvent = false;
                    isTestCompete = true;
                    point.x = (int)e.getX();
                    point.y = (int)e.getY();
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                super.dispatchTouchEvent(e);
                isleftrightEvent = false;
                isTestCompete = false;
                break;
        }
    }
}

?

?

源码已上传。



?

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。