导语
事件分发是一个老生常谈的问题,理解事件分发机制,对于解决日常开发工作中遇到的滑动冲突问题,有着至关重要的作本,这里以阅读源码的方式,对事件分发机制做一个详细的讲解,希望阅读本文后,能对事件分发机制有个深入的理解,解决日常遇到的滑动冲突问题
源码阅读
从Activity开始
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
public boolean superDispatchTouchEvent(MotionEvent event) {
return mDecor.superDispatchTouchEvent(event);
}
public boolean superDispatchTouchEvent(MotionEvent event) {
return super.dispatchTouchEvent(event);
}
下面就进入了View Group的流程
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
boolean handled = false;
if(actionMasked == MotionEvent.ACTION_DOWN){
mFirstTouchTarget = null;
}
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);
} else {
intercepted = false;
}
} else {
intercepted = true;
}
TouchTarget newTouchTarget = null;
boolean alreadyDispatchedToNewTouchTarget = false;
if (!intercepted) {
if (actionMasked == MotionEvent.ACTION_DOWN) {
if (newTouchTarget == null && childrenCount != 0) {
for (int i = childrenCount - 1; i >= 0; i--) {
if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
newTouchTarget = addTouchTarget(child, idBitsToAssign);
alreadyDispatchedToNewTouchTarget = true;
break;
}
}
}
}
}
if (mFirstTouchTarget == null) {
handled = dispatchTransformedTouchEvent(ev, canceled, null,
TouchTarget.ALL_POINTER_IDS);
} else {
TouchTarget predecessor = null;
TouchTarget target = mFirstTouchTarget;
while (target != null) {
final TouchTarget next = target.next;
if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
handled = true;
} else {
if (dispatchTransformedTouchEvent(ev, cancelChild,
target.child, target.pointerIdBits)) {
handled = true;
}
}
predecessor = target;
target = next;
}
}
return handled;
}
从源码中可以得知,整体上,事件的分发是由Activity自顶向下逐级传播的,通过Activity的dispatchTouchEvent最终访问到DecorView的dispatchTouchEvent方法,
dispatchTouchEvent是事件分发的入口,这里要重点讲解,从上述代码中标注的内容来看,我们可以得知,任何一个事件,都是从Down事件开始的,从dispatchTouchEvent的源码中我们也可以了解到,有很多针对DOWN事件单独处理的逻辑,因此之类解读源码,也分量两个流程讲解,DOWN事件的流程与其他事件的流程
DOWN事件的流程
- 第一步:确定是否需要拦截事件
–理解:DOWN事件到来时,确认是否需要自己拦截处理,前置清空mFirstTouchTarget字段,调用自身的onInterceptTouchEvent来确认是否需要自己主动拦截处理该事件 - 第二步:DOWN事件分发
–若自身不需要拦截DOWN事件,则将事件分发给子VIEW,调用child.dispatchTouchEvent递归询问子view是否能处理该事件,若子view能处理,则记录mFirstTouchTarget,和alreadyDispatchedToNewTouchTarget
–若自身拦截,则直接跳过第二步 - 第三步:真正事件分发,将事件分发给对应View
–根据第二步的结果,已经得知事件是自己处理还是子View处理,自身处理最终会调用自身的onTouchEvent来处理事件,若是子VIEw处理,因DOWN事件的特殊性,在第二步已经调用了child.dispatchTouchEvent,第三步则根据第二步记录的alreadyDispatchedToNewTouchTarget 字段,直接返回已经处理的结果 - 第四步:无
其他事件的分发流程
- 第一步:确定是否需要拦截事件
–理解:根据mFirstTouchTarget字段,判断,若存在能处理事件的子VIEW,调用自身的onInterceptTouchEvent来确认是否需要自己主动拦截处理该事件 - 第二步:无
- 第三步:真正事件分发,将事件分发给对应View
–根据DOWN事件时记录的结果,已经得知事件是自己处理还是子View处理,自身处理最终会调用自身的onTouchEvent来处理事件,若是子VIEw处理,则调用了child.dispatchTouchEvent - 第四步:返回第三步得到的结果给上层。
需要重点理解几个字段
mFirstTouchTarget:在Down事件时记录,子view能否处理事件,能的话后面的新事件交个子view处理
alreadyDispatchedToNewTouchTarget:为了防止多次触发子view的dispatchTouchEvent,用于记录的一个成员变量
总结
在理解上述流程时,是不是发现了我们在处理滑动冲突时,经常会遇到的几个方法
dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent
结合源码阅读,我们可以对这几个函数有更深入的理解
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.e("whqq", "父类dispatchTouchEvent" );
boolean result = super.dispatchTouchEvent(ev);
Log.e("whqq", "父类dispatchTouchEvent结果" + result);
return result;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
Log.e("whqq", "父类onInterceptTouchEvent" );
boolean result = super.onInterceptTouchEvent(e);
Log.e("whqq", "父类onInterceptTouchEvent结果" + result);
return result;
}
@Override
public boolean onTouchEvent(MotionEvent e) {
Log.e("whqq", "父类onTouchEvent" );
boolean result = super.onTouchEvent(e);
Log.e("whqq", "父类onTouchEvent结果" + result);
return result;
}
思考
- 在解决滑动冲突问题时,最应该复写的是onTouchEvent方法,去处理滑动事件,
- 若复写了onInterceptTouchEvent方法,也要注意,既然选择拦截了,就代表要么你已经确认要处理该事件在onTouchEvent中返回true,要么代表问题是因为事件交给子view处理引入了问题,才复写onInterceptTouchEvent事件传递给子view,不然都是错误复写
- 若复写了dispatchTouchEvent方法,记的调用super
阅读全文
下载说明:
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.dandroid.cn/archives/22373,转载请注明出处。
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.dandroid.cn/archives/22373,转载请注明出处。
评论0