ViewDragHelper类,是用来处理View边界拖动相关的类,比如我们这里要用的例子—侧滑拖动关闭页面(类似微信),该功能很明显是要处理在View上的触摸事件,记录触摸点、计算距离、滚动动画、状态回调等,如果我们自己手动实现自然会很麻烦还可能出错,而这个类会帮助我们大大简化工作量。
该类是在Support包中提供,所以不会有系统适配问题,下面我们就来看看他的原理和使用吧。
1.初始化
private ViewDragHelper(Context context, ViewGroup forParent, Callback cb) {
...
mParentView = forParent;//BaseView
mCallback = cb;//callback
final ViewConfiguration vc = ViewConfiguration.get(context);
final float density = context.getResources().getDisplayMetrics().density;
mEdgeSize = (int) (EDGE_SIZE * density + 0.5f);//边界拖动距离范围
mTouchSlop = vc.getScaledTouchSlop();//拖动距离阈值
mScroller = new OverScroller(context, sInterpolator);//滚动器
}
-
mParentView是指基于哪个View进行触摸处理
-
mCallback是触摸处理的各个阶段的回调
-
mEdgeSize是指在边界多少距离内算作拖动,默认为20dp
-
mTouchSlop指滑动多少距离算作拖动,用的系统默认值
-
mScroller是View滚动的Scroller对象,用于处理释触摸放后,View的滚动行为,比如滚动回原始位置或者滚动出屏幕
2.拦截事件处理
该类提供了boolean shouldInterceptTouchEvent(MotionEvent)方法,通常我们需要这么写:
override fun onInterceptTouchEvent(ev: MotionEvent?) =
dragHelper?.shouldInterceptTouchEvent(ev) ?: super.onInterceptTouchEvent(ev)
该方法用于处理mParentView是否拦截此次事件
public boolean shouldInterceptTouchEvent(MotionEvent ev) {
...
switch (action) {
...
case MotionEvent.ACTION_MOVE: {
if (mInitialMotionX == null || mInitialMotionY == null) break;
// First to cross a touch slop over a draggable view wins. Also report edge drags.
final int pointerCount = ev.getPointerCount();
for (int i = 0; i < pointerCount; i++) {
final int pointerId = ev.getPointerId(i);
// If pointer is invalid then skip the ACTION_MOVE.
if (!isValidPointerForActionMove(pointerId)) continue;
final float x = ev.getX(i);
final float y = ev.getY(i);
final float dx = x - mInitialMotionX[pointerId];
final float dy = y - mInitialMotionY[pointerId];
final View toCapture = findTopChildUnder((int) x, (int) y);
final boolean pastSlop = toCapture != null && checkTouchSlop(toCapture, dx, dy);
...
//判断pointer的拖动边界
reportNewEdgeDrags(dx, dy, pointerId);
...
}
saveLastMotion(ev);<