Android开发Android开发经验谈Android开发

二、View 事件分发机制

2018-10-08  本文已影响17人  Yjnull

本文是自己看过一些资料后的总结,如要详细了解事件分发机制,请看「参考」内的文章。

一、事件分发基础认知

1.1 当我们在谈论事件分发时,到底再谈论什么?

1.2 那么 MotionEvent 会在哪些对象之间传递呢?

1.3 事件分发过程中都会经历哪些方法来进行 MotionEvent 的传递?

二、事件分发机制

2.1 Activity 事件分发机制

2.2 ViewGroup 事件分发机制

2.2.1 ViewGroup 怎么判断哪个子 View 被点击了

循环子 View 中,有这么一段代码,用来判断当前 View 是否被点击了

     //child可接受触摸事件:是指child是可见的(VISIBLE);或者虽然不可见,但是位于动画状态。
    if (!canViewReceivePointerEvents(child)
            || !isTransformedTouchPointInView(x, y, child, null)) {
                 ev.setTargetAccessibilityFocus(false);
                 continue;
       }

这里面有两个方法用来判断, canViewReceivePointerEventsisTransformedTouchPointInView
其中canViewReceivePointerEvents判断当前 View 是否能接收到 pointer events ,如果不能接收到,那就直接 continue 循环下一个了。

如果上面判断是可以接受触摸事件的,那么就会去判断触摸坐标(x,y)是否在 child 的可视范围之内。
接下来具体看看 isTransformedTouchPointInView

    protected boolean isTransformedTouchPointInView(float x, float y, View child,
            PointF outLocalPoint) {
        // 首先 new 一个 float 数组,用来存放点击的 x、y 坐标
        final float[] point = getTempPoint();
        point[0] = x;
        point[1] = y;
        transformPointToViewLocal(point, child);
        //这是用来判断点击是否在 View 内的具体方法。
        final boolean isInView = child.pointInView(point[0], point[1]);
        if (isInView && outLocalPoint != null) {
            outLocalPoint.set(point[0], point[1]);
        }
        return isInView;
    }
    final boolean pointInView(float localX, float localY) {
        return localX >= 0 && localX < (mRight - mLeft)
                && localY >= 0 && localY < (mBottom - mTop);
    }

通过这个方法可以看到,View 是怎样判断的。

2.3 View 事件分发机制

btn.setOnTouchListener(new OnTouchListener) {
    @Override
    public boolean onTouch(View v, MotionEvent evnet) {
    // 若在onTouch()返回true,从而使得View.dispatchTouchEvent()直接返回true,事件分发结束
    // 若在onTouch()返回false,从而使得View.dispatchTouchEvent()中跳出If,执行onTouchEvent(event)
        return true;
    }
}
    // && 为短路与,即如果前面条件为 false,将不再往下执行
    // 所以 onTouch() 能够执行需2个前提条件:
    //  1. mOnTouchListener 的值不能为空
    //  2. 当前控件必须是 enable 的。
    if (mOnTouchListener != null
          && (mViewFlags & ENABLED_MASK) == ENABLED
               && mOnTouchListener.onTouch(this, event)) 
     {
           result = true;
     }
    // 对于该类 非 enable 控件,若需监听它的 touch 事件,就必须通过在该控件中重写 onTouchEvent()来实现

参考

https://blog.csdn.net/carson_ho/article/details/54136311
http://www.gcssloop.com/customview/dispatch-touchevent-source
http://gityuan.com/2015/09/19/android-touch/

上一篇 下一篇

猜你喜欢

热点阅读