android事件分发

来源:互联网 发布:两组数据的显著性差异 编辑:程序博客网 时间:2024/06/06 03:28

以前对android view的事件分发总是比较模糊,最近用到这块知识,于是学习了一下,主要参考了网上的一些博客,带U型图那种,讲解的很好懂,还有就是一本书《Android开发艺术探索》,感觉还不错;
纸上得来终觉浅,绝知此事要躬行,写了写小demo梳理一下知识,记下来以备后用;

自定义viewgrou和view,viewgroup三个方法都return super
view和activity两个方法也是return super

Log:activity dispatch =downviewgroup dispatch =downviewgroup intercept =downmyview dispatch =downmyview ontouch =downviewgroup ontouch =downactivity ontouch =downactivity dispatch =moveactivity ontouch =moveactivity dispatch =upactivity ontouch =up

从上面可以看出
1.事件分发的主要流程,由activity到外层viewgroup到内层view,而处理则是由内层view到外层viewgroup再到activity,就是通常说的U型
2.onInterceptTouchEvent默认返回false不拦截
3.为什么到move事件后都只有activity在处理了呢,事件为什么不继续分发下去呢?原因:作为一个view或者viewgroup,如果他不消耗down事件,那此次系列事件就不再分发给他处理

让viewgroup拦截move事件,这里将他的ontouch返回true(都不处理的话,viewgroup的dispatch就没法被调起来了,也就没拦截一说了)
可以看出
1.事件在分发到move时候被viewgroup拦截就不再传递给view了
2.由于down事件被viewgroup处理了,activity就不再调用ontouch了;
3.onInterceptTouchEvent只调用了一次,原因:内层view不消耗事件时这个方法也就没必要多次调用了

将上面稍作修改让view处理ontouch而不是viewgroup
可以看出
1.onInterceptTouchEvent没有拦截down,于是view有机会处理,于是onInterceptTouchEvent被再次调用,这次拦截了move,于是view便无法分发到move及之后的事件;
2.一旦viewgroup拦截了事件,那此次之后的系列事件都会交给他处理

记录几个分发机制

  • 如果view不消耗除down以外的其他事件,那么这个点击事件会消失,此时父元素的ontouch不会调用,并且当前view可以持续收到后续事件,最终这些消失的点击事件会传递给activity处理
activity dispatch =downviewgroup dispatch =downviewgroup intercept =downmyview dispatch =downmyview ontouch =down------------------------------activity dispatch =moveviewgroup dispatch =moveviewgroup intercept =movemyview dispatch =movemyview ontouch =move------------------------------activity ontouch =moveactivity dispatch =upviewgroup dispatch =upviewgroup intercept =upmyview dispatch =upmyview ontouch =upactivity ontouch =up
  • ontouchlistener的ontouch返回true,那么ontouchEvent不会被调用
  • 使用requestDisallowInterceptTouchEvent不让viewgroup拦截view的事件

接下来看源码

            // 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;            }

可以看出调用onInterceptTouchEvent的条件,down事件,或者mFirstTouchTarget != null即子view处理了事件;这也印证了上面例子中onInterceptTouchEvent被多次调用的情况;还由disallowIntercept控制,这个FLAG_DISALLOW_INTERCEPT,很眼熟,就是子view调用requestDisallowInterceptTouchEvent不让viewgroup拦截;
不再过多贴代码,DEBUG跟一下代码,也不要拘泥于代码细节,把握主要的代码流程就行;
另外,网上U型图中view的ontouch return false或super事件就继续向上传,不太严谨;super应该是由返回值来确定的,所以对于可点击的view super其实是返回true的,上层view也无法收到ontouch;

原创粉丝点击