ViewDragHelper實例學習筆記

github上的一個開源項目:https://github.com/BlueMor/DragLayout,

效果圖:

側滑效果的實現主要用的是ViewDragHelper,實現了對TouchEvent中的action處理進行了封裝,

使用者不必操心在側滑的過程中如何處理TouchEvent中的ACTION_DOWN、ACTION_MOVE和ACTION_UP事件,

而只需實現回調接口ViewDragHelper.Callback()中的方法就ok了,在此項目中實現的接口:

private ViewDragHelper.Callback dragHelperCallback = new ViewDragHelper.Callback() {

   @Override
        public boolean tryCaptureView(View child, int pointerId) {//當前view是否允許拖動
            return true;
        }
    @Override
        public int getViewHorizontalDragRange(View child) {<span style="font-family: Arial, Helvetica, sans-serif;">//橫向拖動的最大距離</span>
            return width; 
        }
  @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            super.onViewReleased(releasedChild, xvel, yvel);//ACTION_UP事件後調用其方法
            if (xvel > 0) {
                open();
            } else if (xvel < 0) {
                close();
            } else if (releasedChild == vg_main && mainLeft > range * 0.3) {
                open();
            } else if (releasedChild == vg_left && mainLeft > range * 0.7) {
                open();
            } else {
                close();
            }
        }

        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {//返回橫向座標左右邊界值
            if (mainLeft + dx < 0) { 
                return 0 ;//0
            } else if (mainLeft + dx > range) {
                return range;//
            } else {
                return left;
            }
        }

    @Override
        public void onViewPositionChanged(View changedView, int left, int top,
                int dx, int dy) {//view在拖動過程座標發生變化時會調用此方法,包括兩個時間段:手動拖動和自動滾動
        	
            if (changedView == vg_main) {
            	Log.d("draglayout","changedview is vg main");
                mainLeft = left;
            } else {
                mainLeft = mainLeft + left;
                Log.d("draglayout","changedview is vg left");
            }
            if (mainLeft < 0) {
                mainLeft = 0;
            } else if (mainLeft > range) {
                mainLeft = range;
            }


            if (isShowShadow) {
                iv_shadow.layout(mainLeft, 0, mainLeft + width, height);
            }
            if (changedView == vg_left) {
                vg_left.layout(0, 0, width, height);
                vg_main.layout(mainLeft, 0, mainLeft + width, height);
            }


            dispatchDragEvent(mainLeft);
        }
    };
在此接口中基本沒有對touchevent事件的處理,那這些方法是怎麼與touchevent時間聯繫起來的?

在touchevent事件處理中DragLayout是直接調用了ViewDragHelper中的processTouchEvent方法:

  public boolean onTouchEvent(MotionEvent e) {
        try {
            dragHelper.processTouchEvent(e);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return false;
    }

在processTouchEvent中對ACTION_DOWN、ACTION_MOVE和ACTION_UP事件進行了處理:

1.在ACTION_DOWN中調用回調接口中的tryCaptureView方法,看當前touch的view是否允許拖動

    在此項目中的是直接return true,兩個view都是允許拖動的

2.在ACTION_MOVE中,view的座標發生改變,調用回調接口中的onViewPositionChanged方法,

  根據座標信息對view進行layout,通過ViewHelper這個類中的setScaleX、setScaleY方法,實現在

  拖動的過程中view在XY座標上進行相應比例的縮放;

3.在ACTION_UP後調用回調接口中的onViewReleased方法,此方法中一個重要的任務是在ACTION_UP事件

  後,實現view的自動滑動,這裏主要是使用了ViewDragHelper中smoothSlideViewTo方法,start了ViewDragHelper

  中的mScroller:

        mScroller.startScroll(startLeft, startTop, dx, dy, duration);

        setDragState(STATE_SETTLING);
    然後通過方法ViewCompat.postInvalidateOnAnimation(this)調用view的 computeScroll() 方法:

    public void computeScroll() {
        if (dragHelper.continueSettling(true)) {
            ViewCompat.postInvalidateOnAnimation(this);
        }
    }

  ViewDragHelper的中的continueSettling方法會調用的mScroller.computeScrollOffset();方法,

來判斷滾動是否結束,並在獲取mScroller.getCurrX() 的值後,調用回調接口的onViewPositionChanged方法對view進行layout,

自此完成了手動拖和ACTION_UP後自動滾動的兩個過程,大致流程圖如下:






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章