【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 五 )(二)

简介: 【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 五 )(二)

四、触摸事件被拦截的调用链分析


如果上述事件分发方法 dispatchTransformedTouchEvent 返回 true , 就会创建 newTouchTarget 值 , 该值不会为空 , 同时 mFirstTouchTarget 不为空 ;


如果上述事件分发方法 dispatchTransformedTouchEvent 返回 false , 此时 newTouchTarget 值 , 就会为空 , 同时 mFirstTouchTarget 为空 ;


假设事件已经被消费了 , if (newTouchTarget == null && mFirstTouchTarget != null) 分支的代码不会被命中 , 继续向下分析 ;



同理如果事件被消费 , 也不会命中 if (mFirstTouchTarget == null) 分支 ;



下面讨论另外一种情况 , 就是父容器拦截触摸事件 ;


调用 ViewGroup | requestDisallowInterceptTouchEvent 可以设置是否拦截触摸事件 , 如果传入 true 则拦截触摸事件 , 如果传入 false , 则不拦截触摸事件 ;


在该 ViewGroup | requestDisallowInterceptTouchEvent 方法中 , 会修改 mGroupFlags 值 ;


 

@Override
    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
      // 设置父容器是否要拦截子组件的触摸事件
        if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) {
            // We're already in this state, assume our ancestors are too
            return;
        }
        if (disallowIntercept) {
            mGroupFlags |= FLAG_DISALLOW_INTERCEPT;
        } else {
            mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
        }
        // Pass it up to our parent
        if (mParent != null) {
            mParent.requestDisallowInterceptTouchEvent(disallowIntercept);
        }
    }


在 ViewGroup | dispatchTouchEvent 方法中 , 通过 mGroupFlags & FLAG_DISALLOW_INTERCEPT 判定父容器是否需要拦截子组件的触摸事件 , 该值最终影响 ViewGroup | dispatchTouchEvent | intercepted 局部变量的判断 ;


       

// Check for interception.
            final boolean intercepted;
            if (actionMasked == MotionEvent.ACTION_DOWN
                    || mFirstTouchTarget != null) {
                final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
                if (!disallowIntercept) {
                    intercepted = onInterceptTouchEvent(ev);
                    ev.setAction(action); // restore action in case it was changed
                } else {
                    intercepted = false;
                }
            } else {
                // There are no touch targets and this action is not an initial down
                // so this view group continues to intercept touches.
                intercepted = true;
            }


假如父容器要拦截事件 , 此时 intercepted 值为 true , if (!canceled && !intercepted) { 分支就不会被命中 , 该分支是事件分发的核心逻辑 , 全都被屏蔽了 , 最终 :


ViewGroup | dispatchTouchEvent | newTouchTarget 局部变量

ViewGroup | mFirstTouchTarget 成员变量


都为空 , 执行到 if (mFirstTouchTarget == null) 分支时 , 会命中该分支 , 进而调用 dispatchTransformedTouchEvent(ev, canceled, null, TouchTarget.ALL_POINTER_IDS) 方法 , 在 dispatchTransformedTouchEvent 方法中 , 如果 child 为空 , 则会调用父类的 super.dispatchTouchEvent 方法 ;


ViewGroup 继承自 View , 在 ViewGroup 中调用 super.dispatchTouchEvent 方法 , 就是调用 View 的 dispatchTouchEvent 方法 ;


super.dispatchTouchEvent(event) 方法消费的是父容器自己的事件 ;


child.dispatchTouchEvent(event) 方法消费的是子组件的事件 ;


 

private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
            View child, int desiredPointerIdBits) {
        final boolean handled;
        final int oldAction = event.getAction();
        if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
            event.setAction(MotionEvent.ACTION_CANCEL);
            if (child == null) {
                handled = super.dispatchTouchEvent(event);
            } else {
                handled = child.dispatchTouchEvent(event);
            }
            event.setAction(oldAction);
            return handled;
        }
        ...
  }


ViewGroup | dispatchTouchEvent 相关代码 :


@UiThread
public abstract class ViewGroup extends View implements ViewParent, ViewManager {
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
  ...
      // 如果上述事件分发方法 dispatchTransformedTouchEvent 返回 true 
      // 就会创建 newTouchTarget 值 , 该值不会为空 , 同时 mFirstTouchTarget 不为空
      // 如果上述事件分发方法 dispatchTransformedTouchEvent 返回 false 
      // 此时 newTouchTarget 值 , 就会为空 , 同时 mFirstTouchTarget 为空 
                    if (newTouchTarget == null && mFirstTouchTarget != null) {
                        // Did not find a child to receive the event.
                        // Assign the pointer to the least recently added target.
                        newTouchTarget = mFirstTouchTarget;
                        while (newTouchTarget.next != null) {
                            newTouchTarget = newTouchTarget.next;
                        }
                        newTouchTarget.pointerIdBits |= idBitsToAssign;
                    }
                }
            }
    // 如果事件被消费 , 事件分发方法 dispatchTransformedTouchEvent 返回 true 
    // 就会创建 newTouchTarget 值 , 该值不会为空 , 同时 mFirstTouchTarget 不为空
    // 反之
    // 如果上述事件分发方法 dispatchTransformedTouchEvent 返回 false 
    // 此时 newTouchTarget 值 , 就会为空 , 同时 mFirstTouchTarget 为空 
    // 
    // 还有一个逻辑就是 , 如果该事件被父容器拦截 , mFirstTouchTarget 也是 null 值
    // 调用 dispatchTransformedTouchEvent , 但是传入的子组件时 null 
    // 在 dispatchTransformedTouchEvent 方法中触发调用 if (child == null) 分支的 
    // handled = super.dispatchTouchEvent(event) 方法 , 调用父类的事件分发方法 
            // Dispatch to touch targets.
            if (mFirstTouchTarget == null) {
              // 事件没有被消费的分支 
                // No touch targets so treat this as an ordinary view.
                handled = dispatchTransformedTouchEvent(ev, canceled, null,
                        TouchTarget.ALL_POINTER_IDS);
            }
  ...
  }
    /**
     * Adds a touch target for specified child to the beginning of the list.
     * Assumes the target child is not already present.
     */
    private TouchTarget addTouchTarget(@NonNull View child, int pointerIdBits) {
        final TouchTarget target = TouchTarget.obtain(child, pointerIdBits);
        target.next = mFirstTouchTarget;
        mFirstTouchTarget = target;
        return target;
    }
    /**
     * Transforms a motion event into the coordinate space of a particular child view,
     * filters out irrelevant pointer ids, and overrides its action if necessary.
     * If child is null, assumes the MotionEvent will be sent to this ViewGroup instead.
     */
    private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
            View child, int desiredPointerIdBits) {
        final boolean handled;
        // Canceling motions is a special case.  We don't need to perform any transformations
        // or filtering.  The important part is the action, not the contents.
        final int oldAction = event.getAction();
        if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
            event.setAction(MotionEvent.ACTION_CANCEL);
            if (child == null) {
                handled = super.dispatchTouchEvent(event);
            } else {
                handled = child.dispatchTouchEvent(event);
            }
            event.setAction(oldAction);
            return handled;
        }
        ...
  }
}



目录
相关文章
|
4月前
|
XML Java Android开发
Android Studio App开发之捕获屏幕的变更事件实战(包括竖屏与横屏切换,回到桌面与切换到任务列表)
Android Studio App开发之捕获屏幕的变更事件实战(包括竖屏与横屏切换,回到桌面与切换到任务列表)
38 0
|
4月前
|
小程序 JavaScript 前端开发
微信小程序(十七)小程序监听返回键跳转事件(安卓返回也适用)
onUnload:function(){ wx.redirectTo({ url: '../index/index' }) wx.navigateTo({ url: '../index/index' }) wx.switchTab({ url: '../../member/member' }) }
297 0
|
8月前
|
Android开发
Android PackageManagerService源码分析和APK安装原理详解
Android PackageManagerService源码分析和APK安装原理详解
200 1
|
4月前
|
Android开发 容器
[Android]View的事件分发机制(源码解析)
[Android]View的事件分发机制(源码解析)
36 0
|
4月前
|
消息中间件 缓存 安全
android开发,使用kotlin学习消息机制Handler
android开发,使用kotlin学习消息机制Handler
78 0
|
4月前
|
安全 Android开发 Kotlin
android开发,使用kotlin学习Android权限机制
android开发,使用kotlin学习Android权限机制
35 0
|
4月前
|
XML Java Android开发
Android App事件交互Event之模仿京东App实现下拉刷新功能(附源码 可直接使用)
Android App事件交互Event之模仿京东App实现下拉刷新功能(附源码 可直接使用)
32 0
Android App事件交互Event之模仿京东App实现下拉刷新功能(附源码 可直接使用)
|
4月前
|
XML Java Android开发
Android App事件交互中辨别缩放与旋转手指的讲解与实战(附源码 可直接使用)
Android App事件交互中辨别缩放与旋转手指的讲解与实战(附源码 可直接使用)
36 0
|
4月前
|
XML Java Android开发
Android App事件交互中区分点击和长按动作以及识别手势滑动方向的讲解及实战(附源码 可直接使用)
Android App事件交互中区分点击和长按动作以及识别手势滑动方向的讲解及实战(附源码 可直接使用)
60 0
|
4月前
|
XML Java Android开发
Android App开发触摸事件中手势事件Event的分发流程讲解与实战(附源码 简单易懂)
Android App开发触摸事件中手势事件Event的分发流程讲解与实战(附源码 简单易懂)
43 0