- CompoundButton 源码分析
- LinearLayout 源码分析
- SearchView 源码解析
- LruCache 源码解析
- ViewDragHelper 源码解析
- BottomSheets 源码解析
- Media Player 源码分析
- NavigationView 源码解析
- Service 源码解析
- Binder 源码分析
- Android 应用 Preference 相关及源码浅析 SharePreferences 篇
- ScrollView 源码解析
- Handler 源码解析
- NestedScrollView 源码解析
- SQLiteOpenHelper/SQLiteDatabase/Cursor 源码解析
- Bundle 源码解析
- LocalBroadcastManager 源码解析
- Toast 源码解析
- TextInputLayout
- LayoutInflater 和 LayoutInflaterCompat 源码解析
- TextView 源码解析
- NestedScrolling 事件机制源码解析
- ViewGroup 源码解析
- StaticLayout 源码分析
- AtomicFile 源码解析
- AtomicFile 源码解析
- Spannable 源码分析
- Notification 之 Android 5.0 实现原理
- CoordinatorLayout 源码分析
- Scroller 源码解析
- SwipeRefreshLayout 源码分析
- FloatingActionButton 源码解析
- AsyncTask 源码分析
- TabLayout 源码解析
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
4.2. shouldInterceptTouchEvent() 方法的实现
在这里我们假设大家都清楚了 Android 的事件分发机制,如果不清楚请看 这里 ,要想处理触摸事件,我们需要在 onInterceptTouchEvent(MotionEvent ev) 方法里判断是否需要拦截这次触摸事件,如果此方法返回 true 则触摸事件将会交给 onTouchEvent(MotionEvent event) 处理,这样我们就能处理触摸事件了,所以我们在上面的使用方法里会这样写:
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return mDragger.shouldInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mDragger.processTouchEvent(event);
return true;
}这样就将是否拦截触摸事件,以及处理触摸事件委托给 ViewDragHelper 来处理了,所以我们先来看看 ViewDragHelper 中 shouldInterceptTouchEvent(); 方法的实现:
public boolean shouldInterceptTouchEvent(MotionEvent ev) {
//获取 action
final int action = MotionEventCompat.getActionMasked(ev);
//获取 action 对应的 index
final int actionIndex = MotionEventCompat.getActionIndex(ev);
//如果是按下的 action 则重置一些信息,包括各种事件点的数组
if (action == MotionEvent.ACTION_DOWN) {
// Reset things for a new event stream, just in case we didn't get
// the whole previous stream.
cancel();
}
//初始化 mVelocityTracker
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(ev);
//根据 action 来做相应的处理
switch (action) {
case MotionEvent.ACTION_DOWN: {
final float x = ev.getX();
final float y = ev.getY();
//获取这个事件对应的 pointerId,一般情况下只有一个手指触摸时为 0
//两个手指触摸时第二个手指触摸返回的 pointerId 为 1,以此类推
final int pointerId = MotionEventCompat.getPointerId(ev, 0);
//保存点的数据
//TODO (1)
saveInitialMotion(x, y, pointerId);
//获取当前触摸点下最顶层的子 View
//TODO (2)
final View toCapture = findTopChildUnder((int) x, (int) y);
//如果 toCapture 是已经捕获的 View,而且正在处于被释放状态
//那么就重新捕获
if (toCapture == mCapturedView && mDragState == STATE_SETTLING) {
tryCaptureViewForDrag(toCapture, pointerId);
}
//如果触摸了边缘,回调 callback 的 onEdgeTouched() 方法
final int edgesTouched = mInitialEdgesTouched[pointerId];
if ((edgesTouched & mTrackingEdges) != 0) {
mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId);
}
break;
}
//当又有一个手指触摸时
case MotionEventCompat.ACTION_POINTER_DOWN: {
final int pointerId = MotionEventCompat.getPointerId(ev, actionIndex);
final float x = MotionEventCompat.getX(ev, actionIndex);
final float y = MotionEventCompat.getY(ev, actionIndex);
//保存触摸信息
saveInitialMotion(x, y, pointerId);
//因为同一时间 ViewDragHelper 只能操控一个 View,所以当有新的手指触摸时
//只讨论当无触摸发生时,回调边缘触摸的 callback
//或者正在处于释放状态时重新捕获 View
if (mDragState == STATE_IDLE) {
final int edgesTouched = mInitialEdgesTouched[pointerId];
if ((edgesTouched & mTrackingEdges) != 0) {
mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId);
}
} else if (mDragState == STATE_SETTLING) {
// Catch a settling view if possible.
final View toCapture = findTopChildUnder((int) x, (int) y);
if (toCapture == mCapturedView) {
tryCaptureViewForDrag(toCapture, pointerId);
}
}
break;
}
//当手指移动时
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 = MotionEventCompat.getPointerCount(ev);
for (int i = 0; i < pointerCount; i++) {
final int pointerId = MotionEventCompat.getPointerId(ev, i);
final float x = MotionEventCompat.getX(ev, i);
final float y = MotionEventCompat.getY(ev, i);
//获得拖拽偏移量
final float dx = x - mInitialMotionX[pointerId];
final float dy = y - mInitialMotionY[pointerId];
//获取当前触摸点下最顶层的子 View
final View toCapture = findTopChildUnder((int) x, (int) y);
//如果找到了最顶层 View,并且产生了拖动(checkTouchSlop() 返回 true)
//TODO (3)
final boolean pastSlop = toCapture != null && checkTouchSlop(toCapture, dx, dy);
if (pastSlop) {
//根据 callback 的四个方法 getView[Horizontal|Vertical]DragRange 和
//clampViewPosition[Horizontal|Vertical]来检查是否可以拖动
final int oldLeft = toCapture.getLeft();
final int targetLeft = oldLeft + (int) dx;
final int newLeft = mCallback.clampViewPositionHorizontal(toCapture,
targetLeft, (int) dx);
final int oldTop = toCapture.getTop();
final int targetTop = oldTop + (int) dy;
final int newTop = mCallback.clampViewPositionVertical(toCapture, targetTop,
(int) dy);
final int horizontalDragRange = mCallback.getViewHorizontalDragRange(
toCapture);
final int verticalDragRange = mCallback.getViewVerticalDragRange(toCapture);
//如果都不允许移动则跳出循环
if ((horizontalDragRange == 0 || horizontalDragRange > 0
&& newLeft == oldLeft) && (verticalDragRange == 0
|| verticalDragRange > 0 && newTop == oldTop)) {
break;
}
}
//记录并回调是否有边缘触摸
reportNewEdgeDrags(dx, dy, pointerId);
if (mDragState == STATE_DRAGGING) {
// Callback might have started an edge drag
break;
}
//如果产生了拖动则调用 tryCaptureViewForDrag()
//TODO (4)
if (pastSlop && tryCaptureViewForDrag(toCapture, pointerId)) {
break;
}
}
//保存触摸点的信息
saveLastMotion(ev);
break;
}
//当有一个手指抬起时,清除这个手指的触摸数据
case MotionEventCompat.ACTION_POINTER_UP: {
final int pointerId = MotionEventCompat.getPointerId(ev, actionIndex);
clearMotionHistory(pointerId);
break;
}
//清除所有触摸数据
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL: {
cancel();
break;
}
}
//如果 mDragState 等于正在拖拽则返回 true
return mDragState == STATE_DRAGGING;
}
上面就是整个 shouldInterceptTouchEvent() 的实现,上面的注释也足够清楚了,我们这里就先不分析某一种触摸事件,大家可以看到我上面留了几个 TODO,下文会一起分析,这里我假设大家都已经对触摸事件分发处理都有充分的理解了,我们下面就直接看 ViewDragHelper 里 processTouchEvent() 方法的实现。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论