Android源码_View事件分发

0,参考

Touch事件传递流程详细剖析

收不到ACTION_MOVE事件

Android源码

1-1,测试Demo的xml样例

(A、B继承Framelayout;C继承View,未修改任何参数)

<LinearLayout>
<A100>
	<B110>
		<C111>
		</C111>
		
		<C112>
		</C112>
	</B110>
	
	<B120>
	</B120>
</A100>

<A200>
	<B210>
		<C211>
		</C211>
	</B210>
	
	<B220>
	</B220>
</A200>

<A300>
	<B310>
	</B310>
</A300>
</LinearLayout>

1-2,全部都是默认值时的时序图(默认值 = false)

 

1-3,修改函数返回值时的时序图

 dispatchTouchEventonInterceptTouchEventonTouchEvent
A

A.dispatch = true

A.onIntercept = true

A.onTouch = true

B

B.dispatch = true

B.onIntercept = true

B.onTouch = true

C

C.dispatch = true

无实现

 

C.onTouch = true

 

 

 

2-0,提问

1)C111的点击事件,DecorView会dispatch给A300么

2)用户从A300滑动到A100,会触发A100的事件分发么

3)dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent的简化逻辑

4)为什么修改dispatchTouchEvent或onTouchEvent的返回值时,会调用多次

2-1,C111的点击事件,DecorView会dispatch给A300嘛

不会,因为被不符合条件;(父类判断、坐标点判断),代码段如下:

#ViewGroup.java
    public boolean dispatchTouchEvent(MotionEvent ev) {
        ...
		
		View childWithAccessibilityFocus = ev.isTargetAccessibilityFocus()
                        ? findChildWithAccessibilityFocus() : null;
						
		// 通过,目标View,instanceOf去判断是否是某一个父类;若不是,则跳过
		if (childWithAccessibilityFocus != null) {
			if (childWithAccessibilityFocus != child) {
				continue;
			}
			...
		}
		
		// 通过坐标判断是否在范围内;若不在范围内,则跳过
		if (!canViewReceivePointerEvents(child)
				|| !isTransformedTouchPointInView(x, y, child, null)) {
			ev.setTargetAccessibilityFocus(false);
			continue;
		}
		...
    }
#ViewGroup.java
    private View findChildWithAccessibilityFocus() {
        ViewRootImpl viewRoot = getViewRootImpl();
        if (viewRoot == null) {
            return null;
        }

        View current = viewRoot.getAccessibilityFocusedHost();
        if (current == null) {
            return null;
        }

        ViewParent parent = current.getParent();
        while (parent instanceof View) {
            if (parent == this) {
                return current;
            }
            current = (View) parent;
            parent = current.getParent();
        }

        return null;
    }
#ViewGroup.java
    protected boolean isTransformedTouchPointInView(float x, float y, View child,
            PointF outLocalPoint) {
        final float[] point = getTempPoint();
        point[0] = x;
        point[1] = y;
        transformPointToViewLocal(point, child);
        final boolean isInView = child.pointInView(point[0], point[1]);
        if (isInView && outLocalPoint != null) {
            outLocalPoint.set(point[0], point[1]);
        }
        return isInView;
    }

2-2,从A300滑动到A100,会触发A100的事件分发么

不会,因为ACTION_DOWN时特殊处理,当前事件被A300消化;简化代码如下:

#ViewGroup.java
    public boolean dispatchTouchEvent(MotionEvent ev) {
        ...

        boolean handled = false;
        if (onFilterTouchEventForSecurity(ev)) { // 确定屏幕状态为正常状态(未被遮挡等)
            final int action = ev.getAction();
            final int actionMasked = action & MotionEvent.ACTION_MASK;

            // 首次按下时,ACTION_DOWN特殊处理
            if (actionMasked == MotionEvent.ACTION_DOWN) {
                cancelAndClearTouchTargets(ev);
                resetTouchState();
            }
			
			... 内有递归

            // 结束,ACTION_UP特殊处理
            if (canceled
                    || actionMasked == MotionEvent.ACTION_UP
                    || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
                resetTouchState();
            }
        }

        ...
        return handled;
    }

2-3,dispatch、onIntercept、onTouch的简化逻辑

#ViewGroup.java
    public void dispatchTouchEventInner(MotionEvent ev) {
        boolean intercepted = onInterceptTouchEvent(ev);
        
        // 如果不向子控件传递,子控件也不可能消费事件
        if (!intercepted){
            // 其他事件时,子控件可能进入递归,也可能调用onTouchEvent结束事件分发
            // 这个canceled会动态修改的
            dispatchTransformedTouchEvent(ev, canceled, child, bits);
        }
    }
    
    private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel, View child, int desiredPointerIdBits) {
        if (满足某些条件,退出递归) {
            return false;
        }
    
        boolean handled;
        if (null == child) {
            handled = onTouchEvent(event); // 调用onTouch方法
        } else {
            handled = child.dispatchTouchEvent(event); // 当child == this时,进入递归
        }
        return handled;
    }

2-4,为什么修改dispatch或onTouch的返回值时,会调用多次

当dispatchTouchEvent的返回值为true,(onTouchEvent 为true最终也是影响它),会进入2-3的递归逻辑

3,总结

1,默认值都是false,ACTION_MOVE不出现

2,dispatchTouchEvent、onTouchEvent返回true,父控件的onTouchEvent不会再执行,并且,一次点击分为ACTION_DOWN + ACTION_UP等多个操作

3,onInterceptTouchEvent返回true,子控件的dispatchTouchEvent、onTouchEvent不会被执行了

 

 

 

ylineSign

QQ群:644213963

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值