android 面试事件分发
开始的Activity和最好的view是没有onInterceptTouchEvent方法的 不能进行对事件的拦截
总论
在我们点击屏幕时,会有下列事件发生:
-
Activity调用
dispathTouchEvent()
方法,把时间传递给Window; -
Window再将事件交给DecorView(DecorView是View的根布局);
-
DecorView再传递给ViewGroup;
Activity ——> Window ——> DecorView ——> ViewGroup
-
ViewGroup调用
dispathTouchEvent()
(分发事件)方法; -
在ViewGroup的
dispathTouchEvent()
方法中还会调用onInterceptTouchEvent()
(拦截事件)。若拦截事件返回为true,表示拦截,事件不会向下层的ViewGroup或者View传递;false,表示不拦截,继续分发事件。默认是false,可以重写onInterceptTouchEvent()改为true。View没有onInterceptTouchEvent()方法,因为View不会再向下层分发事件。 -
事件在ViewGroup和ViewGroup、ViewGroup和View之间进行传递,最终到达View;
-
View调用
dispathTouchEvent()
方法,然后在OnTouchEvent()
进行处理事件;OnTouchEvent() 返回true,表示消耗此事件,不再向下传递;返回false,表示不消耗事件,交回上层处理。
流程图
图片来源:http://gityuan.com/2015/09/19/android-touch/
View不处理事件
View处理事件
事件拦截
常见问题
-
怎么拦截事件
ViewGroup通过
onInterceptTouchEvent()
方法拦截。返回true:拦截事件,不再向下传递;
返回false:不拦截,继续向下传递;
-
子View对事件的处理会有什么影响
子View消费事件:不会再向ViewGroup通知;
子View没有消费事件:事件会反向往上传递,这时父View(ViewGroup)可以进行消费,如果还是没有被消费的话,最后会到Activity的onTouchEvent()函数;
-
子View如何防止被父View拦截
子View可调用requestDisallowInterceptTouchEvent方法,来设置disallowIntercept=true,从而阻止父ViewGroup的onInterceptTouchEvent拦截操作;
-
如果View没有消费ACTION_DOWN事件,则之后的ACTION_MOVE等事件都不会再接收。
-
onTouch与onTouchEvent
onTouch能够得到执行需要两个前提条件,第一mOnTouchListener的值不能为空,第二当前点击的控件必须是enable的。
onTouch优先于onTouchEvent执行。如果在onTouch方法中通过返回true将事件消费掉,onTouchEvent将不会再执行。
-
onTouch与onClick
onClick事件藏在onTouchEvent事件的ACTION_UP中,也就是标示的performClick,这样结合上面onTouch与onTouchEvent事件的关系,可以很容易得到:
① 触摸事件先执行(onTouch>onClick);
② 触摸事件返回值影响点击事件(前者影响后者,而后者不影响前者);
③ onTouch方法的返回值改为true时,只执行onTouch事件,不执行onClick事件,当然也不执行onTouchEvent事件。