当前位置: 代码迷 >> Android >> android-自定义左滑右滑菜单
  详细解决方案

android-自定义左滑右滑菜单

热度:36   发布时间:2016-04-27 23:18:37.0
android---自定义左滑右滑菜单

没有使用第三方类库,纯代码定制.主要用到的知识如下,

我们知道,不管是自定义View还是系统提供的TextView这些,它们都必须放置在LinearLayout等一些ViewGroup中,因此理论上我们可以很好的理解onMeasure(),onLayout(),onDraw()这三个函数:1.View本身大小多少,这由onMeasure()决定;2.View在ViewGroup中的位置如何,这由onLayout()决定;3.绘制View,onDraw()定义了如何绘制这个View。

一个MeasureSpec封装了父布局传递给子布局的布局要求,每个MeasureSpec代表了一组宽度和高度的要求。一个MeasureSpec由大小和模式组成。它有三种模式:UNSPECIFIED(未指定),父元素部队自元素施加任何束缚,子元素可以得到任意想要的大小;EXACTLY(完全),父元素决定自元素的确切大小,子元素将被限定在给定的边界里而忽略它本身大小;AT_MOST(至多),子元素至多达到指定大小的值。

  它常用的三个函数:

  1.static int getMode(int measureSpec):根据提供的测量值(格式)提取模式(上述三个模式之一)

  2.static int getSize(int measureSpec):根据提供的测量值(格式)提取大小值(这个大小也就是我们通常所说的大小)

  3.static int makeMeasureSpec(int size,int mode):根据提供的大小值和模式创建一个测量值(格式)

public static final int ACTION_DOWN = 0; // 按下事件
public static final int ACTION_UP = 1; // 抬起事件
public static final int ACTION_MOVE = 2; // 手势移动事件
public static final int ACTION_CANCEL = 3; // 取消

还有触摸事件,滚动的实现等,代码注释很详细

public class MainUI extends RelativeLayout {    private Context context;    private FrameLayout middleMenu,leftMenu,rightMenu;    //设置模版    private FrameLayout middlemask;    private Scroller scroller;    //属于自定义view,这里就需要用到这两个构造函数    public MainUI(Context context){        super(context);        inintView(context);    }    public MainUI(Context context, AttributeSet attrs) {        super(context, attrs);        inintView(context);    }    //初始化各种变量    public void inintView(Context context){        this.context = context;        //然后我们需要三个界面布局,这里用framelayout来承载        //设置滑动的是当前content和滑动样式        scroller = 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.BLUE);        rightMenu.setBackgroundColor(Color.GREEN);        middlemask.setBackgroundColor(Color.GRAY);        middlemask.setAlpha(0);        //添加到当前布局        addView(leftMenu);        addView(middleMenu);        addView(rightMenu);        addView(middlemask);        //接下来要测量宽度,好用来给这三个部分分别设置宽度,放在onmeasure中    }    /**这个方法决定view本身的大小     * 这里的两个参数分别是屏幕的宽和高     * @param widthMeasureSpec     * @param heightMeasureSpec     */    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        //中间的宽度正好是整个屏幕        middleMenu.measure(widthMeasureSpec, heightMeasureSpec);        middlemask.measure(widthMeasureSpec, heightMeasureSpec);        //旁边的则最多为屏幕的80%        int realWidth = MeasureSpec.getSize(widthMeasureSpec);        int tempWidthMeasure = MeasureSpec.makeMeasureSpec(                (int)(realWidth*0.8f),MeasureSpec.EXACTLY);        leftMenu.measure(tempWidthMeasure, heightMeasureSpec);        rightMenu.measure(tempWidthMeasure, heightMeasureSpec);    }    /**这个方法决定view在layout中的位置     *四个参数对应屏幕 左上右下     * @param changed     */    @Override    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, r, b);        //右边界左右都要设置        rightMenu.layout(                l + middleMenu.getMeasuredWidth(),                t,                l + middleMenu.getMeasuredWidth()                        + rightMenu.getMeasuredWidth(), b);        //接下来添加滑动事件    }    private boolean isTsetCompete;    /**     * 处理相应的触摸事件     * @param ev     * @return     */    @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        if (!isTsetCompete){            getEventType(ev);            return true;        }        //如果是左右滑动        if (isleftrightmove){            switch(ev.getActionMasked()){                case MotionEvent.ACTION_MOVE:                    //得到滑动距离                    int currScrollX = getScrollX();                    //得到移动距离                    int dis_x = (int)(ev.getX() -point.x);                    //他俩差值肯定在20之间                    int expectX = -dis_x +currScrollX;                    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:                    //判断如果滑动距离大于一半则自动滑动出来,否则滑动回去                    currScrollX = getScrollX();                    if (Math.abs(currScrollX) > leftMenu.getMeasuredWidth() >>1) {                        if (currScrollX < 0) {                            scroller.startScroll(currScrollX, 0, -leftMenu.getMeasuredWidth() - currScrollX, 0);                        }else {                            scroller.startScroll(currScrollX,0,leftMenu.getMeasuredWidth()-currScrollX,0);                        }                    }else{                        scroller.startScroll(currScrollX,0,-currScrollX,0);                    }                    //用于屏幕刷新                    invalidate();                    isleftrightmove = false;                    isTsetCompete = false;                    break;            }        }        return super.dispatchTouchEvent(ev);    }    /**     * 在滑动改变距离的同时改变透明度,这种方式很好,因为会先调用父类的方法,所以不会影响到原来程序的运行     * @param x     * @param y     */    @Override    public void scrollTo(int x, int y) {        super.scrollTo(x, y);        int cruX = Math.abs(getScrollX());        float fo = cruX / (float)middleMenu.getMeasuredWidth();        middlemask.setAlpha(fo);    }    /**     * 滚动条的回调方法     */    @Override    public void computeScroll() {        super.computeScroll();        if (!scroller.computeScrollOffset()){            return;        }        int tempX = scroller.getCurrX();        scrollTo(tempX,0);    }    private Point point = new Point();    private static final int TSET_DIS = 20;    private boolean isleftrightmove;    /**     * 用于判断触摸事件类型的函数     * @param ev     */    private void getEventType(MotionEvent ev) {        switch(ev.getActionMasked()){            case MotionEvent.ACTION_DOWN:                //得到当前坐标                point.x = (int) ev.getX();                point.y = (int) ev.getY();                break;            case MotionEvent.ACTION_MOVE:                int dX = Math.abs((int)ev.getX()-point.x);                int dY = Math.abs((int)ev.getY()-point.y);                //左右滑动                if (dX >=TSET_DIS && dX>dY){                    isleftrightmove = true;                    isTsetCompete = true;                    //为了滑动后可以再次滑动                    point.x = (int) ev.getX();                    point.y = (int) ev.getY();                }else if (dY>=TSET_DIS&&dY>dX){                    isleftrightmove = false;                    isTsetCompete = false;                    point.x = (int) ev.getX();                    point.y = (int) ev.getY();                }                break;            case MotionEvent.ACTION_UP:            case MotionEvent.ACTION_CANCEL:                break;        }    }}

这里写图片描述
这里写图片描述
这里写图片描述

版权声明:本文为博主原创文章,未经博主允许不得转载。

  相关解决方案