您当前的位置: 首页 >  android

韩曙亮

暂无认证

  • 2浏览

    0关注

    1068博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

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

韩曙亮 发布时间:2021-07-01 13:56:30 ,浏览量:2

Android 事件分发 系列文章目录

【Android 事件分发】事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) 【Android 事件分发】事件分发源码分析 ( Activity 中各层级的事件传递 | Activity -> PhoneWindow -> DecorView -> ViewGroup ) 【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 一 ) 【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 二 ) 【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 三 ) 【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 四 | View 事件传递机制 ) 【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 五 )

文章目录
  • Android 事件分发 系列文章目录
  • 前言
  • 一、ViewGroup | dispatchTransformedTouchEvent 方法返回值含义
  • 二、记录被消费的触摸事件
  • 三、触摸事件没有被消费的调用链分析
  • 四、触摸事件被拦截的调用链分析
  • 五、ViewGroup 事件分发相关源码
  • 六、View 事件分发相关源码
  • 总结

前言

接上一篇博客 【Android 事件分发】事件分发源码分析 ( View 事件传递机制 ) , 继续分析 ViewGroup 的事件分发机制后续代码 ;

Activity 事件传递 , 最终调用到了 ViewGroup 的 dispatchTouchEvent 方法 , 在该方法中有调用了 View 的 dispatchTouchEvent 方法 ;

View 的 dispatchTouchEvent 调用完毕后 , 会返回 true 或 false 结果 ;

那么继续回到 ViewGroup 的 dispatchTransformedTouchEvent 方法 , 在该方法中 , 也就是遍历 ViewGroup 子组件时 , 调用遍历的子组件 View 的 dispatchTouchEvent 方法 , 处理相关触摸和点击相关的操作 ;

本博客继续分析 ViewGroup 的后续调用链 ;

一、ViewGroup | dispatchTransformedTouchEvent 方法返回值含义

在 ViewGroup | dispatchTouchEvent 方法中 , 调用 ViewGroup | dispatchTransformedTouchEvent 方法进行事件的转发 , 主要是遍历子组件调用子组件的触摸方法 ;

在 ViewGroup | dispatchTransformedTouchEvent 方法中 , 调用了 View 子组件的 View | dispatchTouchEvent 方法 , 该方法返回 true/false , 那么对应的 ViewGroup | dispatchTransformedTouchEvent 方法也会返回相同的值 ;

由下面的代码可知 , handled 是子组件 child.dispatchTouchEvent 调用返回值 , 返回结果就是 handled , 然后有将该值直接返回 , 说明 View 子组件的 dispatchTouchEvent 调用结果 , 就是 ViewGroup 的 dispatchTransformedTouchEvent 方法的返回结果 ;

ViewGroup | dispatchTransformedTouchEvent 方法的返回值含义 :

① 如果返回 true , 证明 子组件 View 已经将事件消费完毕 , 后续不需要再继续执行遍历了 ; ② 如果返回 false , 证明 子组件并没有将事件消费 , 后续还可以进行触发 ;

public abstract class ViewGroup extends View implements ViewParent, ViewManager {
    private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
            View child, int desiredPointerIdBits) {
		...
                if (child == null) {
                	// 被遍历的 child 子组件为空 
                	// 调用父类的分发方法 
                    handled = super.dispatchTouchEvent(event);
                } else {
                	// 被遍历的 child 子组件不为空 
                    final float offsetX = mScrollX - child.mLeft;
                    final float offsetY = mScrollY - child.mTop;
                    event.offsetLocation(offsetX, offsetY);

					// 子组件分发触摸事件 
					// 此处调用的是 View 组件的 dispatchTouchEvent 方法 ; 
                    handled = child.dispatchTouchEvent(event);

                    event.offsetLocation(-offsetX, -offsetY);
                }
                return handled;
            }
		...
	}
}
二、记录被消费的触摸事件

如果 ViewGroup | dispatchTransformedTouchEvent 方法的返回值为 true , 则会触发记录已经被消费的事件的分支 ; 如果返回 false , 则不会触发 ;

// 正式开始分发触摸事件
// 处理以下两种情况 : 
// ① 情况一 : 子控件触摸事件返回 true 
// ② 情况二 : 子控件触摸事件返回 false 
if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {

记录时 , 同时会创建 TouchTarget , 并赋值给 ViewGroup | dispatchTouchEvent | newTouchTarget 局部变量 ;

// 记录消费事件 
// 添加触摸目标 
newTouchTarget = addTouchTarget(child, idBitsToAssign);

调用 addTouchTarget 方法 , 创建被消费的事件 , 并将创建的值赋值给了 ViewGroup | mFirstTouchTarget 成员 ; 第一次消费事件被赋值 ;

    private TouchTarget addTouchTarget(@NonNull View child, int pointerIdBits) {
        final TouchTarget target = TouchTarget.obtain(child, pointerIdBits);
        target.next = mFirstTouchTarget;
        mFirstTouchTarget = target;
        return target;
    }

完整代码如下 :

@UiThread
public abstract class ViewGroup extends View implements ViewParent, ViewManager {
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
		...
                            // 正式开始分发触摸事件
                            // 处理以下两种情况 : 
                            // ① 情况一 : 子控件触摸事件返回 true 
                            // ② 情况二 : 子控件触摸事件返回 false 
                            if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
                                // Child wants to receive touch within its bounds.
                                // 如果返回值为 true , 说明该事件已经被消费了 
                                // 此时记录这个已经被消费的事件 
                                mLastTouchDownTime = ev.getDownTime();
                                if (preorderedList != null) {
                                    // childIndex points into presorted list, find original index
                                    for (int j = 0; j             
关注
打赏
1663594092
查看更多评论
0.0471s