ViewDragHelper场景:
ViewDragHelper解决了Android中手势处理过于复杂的问题,在DrawerLayout出现之前,侧滑菜单都是由第三方开源代码实现的,其中著名的当属MenuDrawer,MenuDrawer重写onTouchEvent方法来实现侧滑效果,代码量很大,实现逻辑也需要很大的耐心才能看懂。
ViewDragHelper初始化:
ViewDragHelper的实例是通过静态工厂方法创建的:ViewDragHelper.create(this,1.0f,newViewDragHelper.Callback()
第一个就是当前的ViewGroup,第二个sensitivity,设置touchSlop(一个很小的距离值,只有在前后两次触摸点的距离超过mTouchSlop的值时,我们才把这两次触摸算作是“滑动”),sensitivity越大,mTouchSlop越小,对滑动的检测就越敏感,第三个在用户的触摸过程中会回调相关方法
ViewDragHelper用法:
继承ViewGroup或子类
重写onInterceptTouchEvent
调用return mDragHelper.shouldInterceptTouchEvent(ev);表示是否应该拦截当前的事件
重写onTouchEvent
调用mDragger.processTouchEvent(event);return true;通过processTouchEvent处理事件
Callback方法:
tryCaptureView 返回true表示捕捉view
clampViewPositionHorizontal 处理横向的拖动
clampViewPositionVertical处理纵向的拖动
上述方法需要重写,第一个自动显示重写,后两个需要手动重写,默认返回0
onEdgeDragStarted 表示边界拖动时回调,如果你想在边缘滑动的时候根据滑动距离移动一个子view,调用mDragHelper.captureChildView方法
onViewReleased 手指释放的时候回调
ViewDragHelper实现的方法:
setEdgeTrackingEnabled 处理滑动边缘
settleCapturedViewAt 手指释放返回指定位置
shouldInterceptTouchEvent 表示是否应该拦截当前的事件
processTouchEvent 处理触摸事件
ViewDragHelper注意的坑:
如果子View不消耗事件,那么整个手势(DOWN-MOVE*-UP)都是直接进入onTouchEvent,在onTouchEvent的DOWN的时候就确定了captureView。如果消耗事件,那么就会先走onInterceptTouchEvent方法,判断是否可以捕获,而在判断的过程中会去判断另外两个回调的方法:getViewHorizontalDragRange和getViewVerticalDragRange,只有这两个方法返回大于0的值才能正常的捕获,如果你用Button测试,或者给TextView添加了clickable = true ,都记得重写。
方法的大致的回调顺序:
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状态),接下来MOVE就直接dragTo了。
而当子View消耗事件的时候,就需要走shouldInterceptTouchEvent,MOVE的时候经过一系列的判断(getViewHorizontalDragRange,clampViewPositionVertical等),才能够去tryCaptureView。
参考: