Android 多级组件滑动总结

场景

  • 最近在实现一个需求:全屏的Map组件上增加一个抽屉效果,抽屉里面要求嵌套一个list并实现下拉刷新,上拉加载更多。
  • 这个需求里面设计到,在屏幕不同的位置触发不同的view滑动:map滑动放大缩小,抽屉上下滑动同时list联动滑动;在抽屉里面list组件滑动,触发上下拉刷新组件刷新。

View移动方案总结

  • ViewDragHelper 通过处理ViewGroup中对子View的拖拽处理,本质是对触摸事件的解析类:
ViewDragHelper主要用于处理ViewGroup中对子View的拖拽处理
主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
方式告诉我们;只需要我们指定是否需要移动,移动多少等;
  • 改变view在父View的layout位置来移动,但是只能移动指定的View:
view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  • 改变scrollX和scrollY来移动,但是可以移动所有的子View:
scrollTo(x,y);
scrollBy(xOffset,yOffset);
  • 改变Canvas绘制的位置来移动View的内容:
canvas.drawBitmap(bitmap, left, top, paint)
  • 改变LayoutParams来移动View的内容:
//必须获取父View的LayoutParams 
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)getLayoutParams();
layoutParams.leftMargin = getLeft() + dx;
layoutParams.topMargin = getTop() + dy;
setLayoutParams(layoutParams);

View核心事件

view移动事件处理两大核心回调接口

  • onInterceptTouchEvent:处理事件的分发机制
  • onTouchEvent:处理滑动事件响应

View移动案例实现

public class DrawerLayout extends RelativeLayout {
    public DrawerLayout(@NonNull Context context) {
        super(context);
        init(context);
    }

    public DrawerLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public DrawerLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context){
        mMinHeight = dip2px(MIN_HEIGHT);
        mTouchScope = dip2px(TOUCH_SCOPE);
    }

    private int dip2px(float dpValue) {
        final float scale = getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    private View mDragView;
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        int childCount = getChildCount();
        if (childCount > 0) {
            mDragView = getChildAt(0);
        }
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                int interval = (int) (event.getY() - mDragView.getY());
                if (interval > 0 && interval < mTouchScope) {
                    mTouchState = TOUCH_STATE_SCROLLING;
                    return true;
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (mTouchState == TOUCH_STATE_SCROLLING) {
                    return true;
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                mTouchState = TOUCH_STATE_REST;
                break;
        }
        return false;
    }

    private static final int MIN_HEIGHT = 180;  //DP 最小高度
    private static final int TOUCH_SCOPE = 50;  //DP 触摸区域
    private int mMinHeight = 200;
    private int mTouchScope = 150;
    private float mDownY;
    private float mLastY;
    private int mTouchState = TOUCH_STATE_REST;
    private static final int TOUCH_STATE_REST = 0x01;
    private static final int TOUCH_STATE_SCROLLING = 0x02;
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mDownY = event.getY();
                mLastY = event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                float curMove = event.getY() - mLastY;
                if (mTouchState == TOUCH_STATE_SCROLLING) {
                    ViewGroup.LayoutParams layoutParams = mDragView.getLayoutParams();
                    int height = (int) (layoutParams.height - curMove);
                    if (height >= mMinHeight) {
                        layoutParams.height = height;
                        mDragView.setLayoutParams(layoutParams);
                    }
                }
                mLastY = event.getY();
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                mTouchState = TOUCH_STATE_REST;
                break;
        }
        return mTouchState == TOUCH_STATE_SCROLLING;
    }
}

你可能感兴趣的:(Android 多级组件滑动总结)