Android-事件体系全面总结+实践分析

本文详细分析了Android中事件分发的完整流程,从down事件开始,探讨了当View的onTouchEvent()消费事件、ViewGroup2的onTouchEvent()消费事件、ViewGroup2的onInterceptTouchEvent()拦截后续事件等不同情况下的事件处理逻辑。通过源码解析和实际操作,揭示了事件消费、拦截和传递的细节,有助于深入理解Android事件处理机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

break;
}
}
}
}
}

//在编号7的if条件里面已经把事件下发到了子View,并得到了子View返回的结果
//至此,默认情况下发事件的逻辑结束

//下面消费事件相关的代码,省略
}

//最后返回结果,此方法结束
return handled;
//至此,如果编号8的代码没执行,也就是子View的dispatchTouchEvent没消费事件,那么mFirstTouchTarget的值是空
//结合编号3的条件,可以得出结论:当ViewGroup不拦截事件且它的子View消费事件的时候,mFirstTouchTarget不为空,否则mFirstTouchTarget是空。
}

代码中注释很详细,最终可以得到一个结论:当ViewGroup不拦截down事件且它的子View消费down事件的时候,mFirstTouchTarget不为空,否则mFirstTouchTarget是空。

下面带着这个结论重新看源码,不过这次分析的不是down事件,而是down之后的事件。只看关键部分,上面代码的编号2部分如下:

///2.是否拦截事件,用布尔变量intercepted表示
final boolean intercepted;
if (actionMasked == MotionEvent.ACTION_DOWN
|| mFirstTouchTarget != null) {
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if (!disallowIntercept) {
//这里调用onInterceptTouchEvent()看是否拦截事件
intercepted = onInterceptTouchEvent(ev);
ev.setAction(action);
} else {
intercepted = false;
}
} else {//如果mFirstTouchTarget是空,而且当前事件不是ACTION_DOWN,就拦截事件
//注意此处直接给intercepted赋值而没有调用onInterceptTouchEvent()方法
intercepted = true;
}

首先if里面的actionMasked == MotionEvent.ACTION_DOWN肯定是不成立了,看mFirstTouchTarget != null,如果mFirstTouchTarget不是空,那么说明子View消费了down事件,会执行到intercepted = onInterceptTouchEvent(ev);这一行代码。如果mFirstTouchTarget是空,说明子View没消费down事件,直接else里面intercepted = true;拦截事件。然后看默认情况下的log:

( 1955): MainActivity->dispatchTouchEvent
( 1955): MyViewGroup1–>dispatchTouchEvent
( 1955): MyViewGroup1–>onInterceptTouchEvent
( 1955): MyViewGroup2—>dispatchTouchEvent
( 1955): MyViewGroup2—>onInterceptTouchEvent
( 1955): MyView--------------->dispatchTouchEvent //down事件下发过程结束
( 1955): MyView--------------->onTouchEvent // down事件消费过程开始
( 1955): MyViewGroup2—>onTouchEvent
( 1955): MyViewGroup1–>onTouchEvent
( 1955): MainActivity->onTouchEvent

( 1955): MainActivity->dispatchTouchEvent //move1事件
( 1955): MainActivity->onTouchEvent
( 1955): MainActivity->dispatchTouchEvent //move2事件
( 1955): MainActivity->onTouchEvent

( 1955): MainActivity->dispatchTouchEvent //up事件
( 1955): MainActivity->onTouchEvent

这里顶级的ViewGroup是MainActivity(DecorView),首先down事件下发到子View,然后子View没消费它,又一层层交给父View消费,最终无人消费传回了MainActivity,down事件结束。由上面的源码分析可知,这时的mFirstTouchTarget是空,如果move事件来了,那么直接执行源码编号2部分的else拦截事件,所以后续事件的log就是上面这样不再下发(同时也没有onInterceptTouchEvent()方法的log因为没调用到它)。如果子View消费down事件,mFirstTouchTarget就不是空,后续事件的流程就与down相似了,读者可以修改MyView的onTouchEvent()消费掉down事件试一下消费down事件的情况。

对于后续事件,无非就是拦截不拦截,决定权还是在编号2部分的代码。决定的结果是是否进入编号3的if,进入的话,如果不是down事件的就直接跳出编号

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值