返回介绍

4.​3. processTouchEvent() 方法的实现

发布于 2024-12-23 21:11:40 字数 4632 浏览 0 评论 0 收藏 0

  public void processTouchEvent(MotionEvent ev) {
    final int action = MotionEventCompat.getActionMasked(ev);
    final int actionIndex = MotionEventCompat.getActionIndex(ev);

    ...(省去部分代码)
    switch (action) {
      case MotionEvent.ACTION_DOWN: {
        ...(省去部分代码)
        break;
      }

      case MotionEventCompat.ACTION_POINTER_DOWN: {
        ...(省去部分代码)
        break;
      }

      case MotionEvent.ACTION_MOVE: {
        //如果现在已经是拖拽状态
        if (mDragState == STATE_DRAGGING) {
          final int index = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
          final float x = MotionEventCompat.getX(ev, index);
          final float y = MotionEventCompat.getY(ev, index);
          final int idx = (int) (x - mLastMotionX[mActivePointerId]);
          final int idy = (int) (y - mLastMotionY[mActivePointerId]);

          //拖拽至指定位置
          //TODO (5)
          dragTo(mCapturedView.getLeft() + idx, mCapturedView.getTop() + idy, idx, idy);

          saveLastMotion(ev);
        } else {
          // Check to see if any pointer is now over a draggable view.
          //如果还不是拖拽状态,就检测是否经过了一个 View
          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];

            reportNewEdgeDrags(dx, dy, pointerId);
            if (mDragState == STATE_DRAGGING) {
              // Callback might have started an edge drag.
              break;
            }

            final View toCapture = findTopChildUnder((int) x, (int) y);
            if (checkTouchSlop(toCapture, dx, dy) &&
                tryCaptureViewForDrag(toCapture, pointerId)) {
              break;
            }
          }
          saveLastMotion(ev);
        }
        break;
      }
      //当多个手指中的一个手机松开时
      case MotionEventCompat.ACTION_POINTER_UP: {
        final int pointerId = MotionEventCompat.getPointerId(ev, actionIndex);
        //如果当前点正在被拖拽,则再剩余还在触摸的点钟寻找是否正在 View 上
        if (mDragState == STATE_DRAGGING && pointerId == mActivePointerId) {
          // Try to find another pointer that's still holding on to the captured view.
          int newActivePointer = INVALID_POINTER;
          final int pointerCount = MotionEventCompat.getPointerCount(ev);
          for (int i = 0; i < pointerCount; i++) {
            final int id = MotionEventCompat.getPointerId(ev, i);
            if (id == mActivePointerId) {
              // This one's going away, skip.
              continue;
            }

            final float x = MotionEventCompat.getX(ev, i);
            final float y = MotionEventCompat.getY(ev, i);
            if (findTopChildUnder((int) x, (int) y) == mCapturedView &&
                tryCaptureViewForDrag(mCapturedView, id)) {
              newActivePointer = mActivePointerId;
              break;
            }
          }

          if (newActivePointer == INVALID_POINTER) {
            // We didn't find another pointer still touching the view, release it.
            //如果没找到则释放 View
            //TODO (6)
            releaseViewForPointerUp();
          }
        }
        clearMotionHistory(pointerId);
        break;
      }

      case MotionEvent.ACTION_UP: {
        //如果是拖拽状态的释放则调用
        //releaseViewForPointerUp()
        if (mDragState == STATE_DRAGGING) {
          releaseViewForPointerUp();
        }
        cancel();
        break;
      }

      case MotionEvent.ACTION_CANCEL: {
        if (mDragState == STATE_DRAGGING) {
          dispatchViewReleased(0, 0);
        }
        cancel();
        break;
      }
    }
  }

上面就是 processTouchEvent() 方法的实现,我们省去了部分大致与 shouldInterceptTouchEvent() 相同的逻辑代码,通过事件传递机制我们知道,如果程序已经进入到 processTouchEvent() 中,也就意味着触摸事件就不会再向下传递,都会交给此方法处理,所以在这里我们就需要处理拖拽事件了,通过上面的注释,我们也看到了在 MotionEvent.ACTION_MOVE , MotionEventCompat.ACTION_POINTER_UP , MotionEvent.ACTION_UPMotionEvent.ACTION_CANCEL 都分别进行了处理 ,我们知道触摸事件大致的流程是:

ACTION_DOWN -> ACTION_MOVE -> ... -> ACTION_MOVE -> ACTION_UP

再配合事件的分发机制,我们就能很清晰的分析出一次完整的事件调用过程,所以整个 ViewDragHelper 的拖拽过程也能很清晰的分为三个步骤:

捕获拖拽目标 View -> 拖拽目标 View -> 处理目标 View 释放操作

最后我们再分析上面两段代码的 6 个 TODO:

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文