自定义侧滑面板(SlieMenu)控件详解

自定义控件的三个方法

  1. onMeasure() 测量控件的宽和高
  2. onLayout() 摆放控件的位置
  3. onDraw() 绘制布局

下面看一点下代码:

public class SlideMenu extends ViewGroup {

private float downX;
private float moveX;
private Scroller scroller;

public SlideMenu(Context context) {
    this(context,null);
}



public SlideMenu(Context context, AttributeSet attrs) {
    this(context, null,0);
}

public SlideMenu(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init();
}


private void init() {
    scroller = new Scroller(getContext());
}

/**
 * 设置子View的宽高
 * @param widthMeasureSpec  当前控件的宽度(测量规则)
 * @param heightMeasureSpec 当前控件的高度(测量规则)
 */
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    /*
    leftMenu的宽是指定的450dp,高是matchparent
     */
    //指定SlideMenu的宽高
    View leftMenu = getChildAt(0);
    //宽是子空间指定的宽,高直接是父控件的高
    Log.i(getClass().getSimpleName(),"width : "+leftMenu.getMeasuredWidth());
    leftMenu.measure(leftMenu.getLayoutParams().width,heightMeasureSpec);

    /*
    mainContent的宽和高都是match_parent
     */
    //指定content的宽高
    View mainContent = getChildAt(1);
    mainContent.measure(widthMeasureSpec,heightMeasureSpec);

    super.onMeasure(widthMeasureSpec,heightMeasureSpec);


}

/**
 * 摆放控件的位置
 * @param changed 当前控件的尺寸大小和位置是否发生了改变
 * @param l     left  当前控件的右边距
 * @param t     top   当前控件的顶边距
 * @param r     right 当前控件的右边界
 * @param b     bottom当前控件的下边界
 */
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    /*
    摆放leftMenu的位置,
     */
    View leftMenu = getChildAt(0);
    leftMenu.layout(-leftMenu.getMeasuredWidth(),0,0,b);

    /*
    摆放mainContent的位置
     */
    getChildAt(1).layout(l,t,r,b);


}


@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()){
        case MotionEvent.ACTION_DOWN://按下
            downX = event.getX();//获取按下时的X的坐标
            break;
        case MotionEvent.ACTION_MOVE://滑动
            moveX = event.getX();//获取滑动时的X的坐标

            //将要滑动的距离
            int scroll = (int) (downX - moveX);//这里是一个负值

            //计算将要滚动到的位置,判断是否会超出去  getScroll()右边界相对于当前View X轴的变异量,是个带正负号的值。
            int newScroll = getScrollX() + scroll;

            /*
            scrollTo()滚动到指定的位置
            scrollBy()在原来的基础上滚动
             */
            //如果将要滑动的距离超过了leftMenu的宽,就直接指定X坐标的位置,将leftMenu显示出来
            if (newScroll < -getChildAt(0).getMeasuredWidth()){
                scrollTo(-getChildAt(0).getMeasuredWidth(),0);
            }else if (newScroll>0){//如果向左滑的话,
                scrollTo(0,0);
            } else{
                scrollBy(scroll,0);
            }
            downX = moveX;//必须要将moveX赋值给downX,因为滑动的过程是一小段一小段的滑动
            break;
        case MotionEvent.ACTION_UP://拿起

            Log.i(getClass().getSimpleName(),"getScrollX: "+getScrollX());
            if (getScrollX() <= -(getChildAt(0).getMeasuredWidth())/2.0f){//当leftMenu画出来显示了一半的时候
                scrollTo(-getChildAt(0).getMeasuredWidth(),0);
            }else {//当没有滑出一半的时候
                scrollTo(0,0);
            }
            break;
        default:
            break;
    }
    return true;//消费事件
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
} 
}

注意

onMeasure()测量的时候,得到的值与你在布局文件中写的是有偏差的。

GitHub:https://github.com/godfunc
博客园:http://www.cnblogs.com/godfunc
Copyright ©2019 Godfunc
原文地址:https://www.cnblogs.com/Godfunc/p/6548187.html