ViewDragHelper場景:
ViewDragHelper解決了Android中手勢處理過于復雜的問題,在DrawerLayout出現(xiàn)之前,側滑菜單都是由第三方開源代碼實現(xiàn)的,其中著名的當屬MenuDrawer,MenuDrawer重寫onTouchEvent方法來實現(xiàn)側滑效果,代碼量很大,實現(xiàn)邏輯也需要很大的耐心才能看懂。
ViewDragHelper初始化:
ViewDragHelper的實例是通過靜態(tài)工廠方法創(chuàng)建的:ViewDragHelper.create(this,1.0f,newViewDragHelper.Callback()
第一個就是當前的ViewGroup,第二個sensitivity,設置touchSlop(一個很小的距離值,只有在前后兩次觸摸點的距離超過mTouchSlop的值時,我們才把這兩次觸摸算作是“滑動”),sensitivity越大,mTouchSlop越小,對滑動的檢測就越敏感,第三個在用戶的觸摸過程中會回調(diào)相關方法
ViewDragHelper用法:
繼承ViewGroup或子類
重寫onInterceptTouchEvent
調(diào)用return mDragHelper.shouldInterceptTouchEvent(ev);表示是否應該攔截當前的事件
重寫onTouchEvent
調(diào)用mDragger.processTouchEvent(event);return true;通過processTouchEvent處理事件
Callback方法:
tryCaptureView 返回true表示捕捉view
clampViewPositionHorizontal 處理橫向的拖動
clampViewPositionVertical處理縱向的拖動
上述方法需要重寫,第一個自動顯示重寫,后兩個需要手動重寫,默認返回0
onEdgeDragStarted 表示邊界拖動時回調(diào),如果你想在邊緣滑動的時候根據(jù)滑動距離移動一個子view,調(diào)用mDragHelper.captureChildView方法
onViewReleased?手指釋放的時候回調(diào)
ViewDragHelper實現(xiàn)的方法:
setEdgeTrackingEnabled 處理滑動邊緣
settleCapturedViewAt 手指釋放返回指定位置
shouldInterceptTouchEvent?表示是否應該攔截當前的事件
processTouchEvent 處理觸摸事件
ViewDragHelper注意的坑:
如果子View不消耗事件,那么整個手勢(DOWN-MOVE*-UP)都是直接進入onTouchEvent,在onTouchEvent的DOWN的時候就確定了captureView。如果消耗事件,那么就會先走onInterceptTouchEvent方法,判斷是否可以捕獲,而在判斷的過程中會去判斷另外兩個回調(diào)的方法:getViewHorizontalDragRange和getViewVerticalDragRange,只有這兩個方法返回大于0的值才能正常的捕獲,如果你用Button測試,或者給TextView添加了clickable = true ,都記得重寫。
方法的大致的回調(diào)順序:
shouldInterceptTouchEvent:
DOWN:
getOrderedChildIndex(findTopChildUnder)
->onEdgeTouched
MOVE:
getOrderedChildIndex(findTopChildUnder)
->getViewHorizontalDragRange &
getViewVerticalDragRange(checkTouchSlop)(MOVE中可能不止一次)
->clampViewPositionHorizontal&
clampViewPositionVertical
->onEdgeDragStarted
->tryCaptureView
->onViewCaptured
->onViewDragStateChanged
processTouchEvent:
DOWN:
getOrderedChildIndex(findTopChildUnder)
->tryCaptureView
->onViewCaptured
->onViewDragStateChanged
->onEdgeTouched
MOVE:
->STATE==DRAGGING:dragTo
->STATE!=DRAGGING:
onEdgeDragStarted
->getOrderedChildIndex(findTopChildUnder)
->getViewHorizontalDragRange&
getViewVerticalDragRange(checkTouchSlop)
->tryCaptureView
->onViewCaptured
->onViewDragStateChanged
在TextView(clickable=false)的情況下,沒有編寫getViewHorizontalDragRange方法時,是可以移動的。因為直接進入processTouchEvent的DOWN,然后就onViewCaptured、onViewDragStateChanged(進入DRAGGING狀態(tài)),接下來MOVE就直接dragTo了。
而當子View消耗事件的時候,就需要走shouldInterceptTouchEvent,MOVE的時候經(jīng)過一系列的判斷(getViewHorizontalDragRange,clampViewPositionVertical等),才能夠去tryCaptureView。
參考: