您的位置:首页 > 其它

MotionEvent事件传递个人总结

2015-07-11 10:58 134 查看
在开发过程中,对于复杂的布局,经常需要手动处理MotionEvent的传递和处理。

一、基础知识

总的来说,处理消息的函数有三个:

dispatchTouchEvent():负责消息的传递,原理应该是询问onInterceptTouchEvent()来判断是否拦截,是则直接传递给当前view的onTouchEvent(),否则传递给child的dispatchTouchEvent()
。对于一个viewgroup来说,只要parent没有拦截,MotionEvent就能被该函数接收到。
onInterceptTouchEvent():正如上面所提到,用于判断是否拦截的函数。不同的是,如果已经某ViewGroup的TouchEvent事件已经被拦截(如ACTION_DOWN),则后续的事件不会再次询问是否拦截。
onTouchEvent():MotionEvent的消费事件,必须消费ACTION_DOWN才能接收到后续的MotionEvent。另外,如果Parent消费了MotionEvent,则后续事件也不会传递给Child了。(例如,如果全部控件都没有消费MotionEvent,则会被Activity消费,后续不论哪个函数都不会收到其他MotionEvent)。特别的,onTouchEventListener优先级高于onTouchEvent(),因此,继承一个View去处理MotionEvent是没有任何意义的。

所谓消费,即返回True。

二、基本技巧

对于一个View来说,如果想要接受到所有的MotionEvent,必须满足两个条件:1)onTouchEvent消费了ACTION_DOWN。2)全部Parent都没有拦截。对于第二个条件,可以通过getParent().requestDisallowInterceptTouchEvent(true);来强制满足。
如果想让MotionEvent事件贯穿整个布局,可以在子View上消费ACTION_DOWN,然后通过重写各级ViewParent的dispatchTouchEvent()来使用。
onInterceptTouchEvent() 的使用。onInterceptTouchEvent()属于辅助型的函数,因此即使重写了该函数,也不会打乱ViewParent本身的事件处理机制。不好的地方在于,onInterceptTouchEvent()只能下拦截的命令,拦截后事件将交由onTouchEvent()处理,并且不能够取消拦截。因此,仅仅重写此方法,达不到灵活的事件传递效果。
dispatchTouchEvent()的使用。一旦重写dispatchTouchEvent(),相当于重新定制事件传递机制,因此,开发者需要增加一定的工作量来维护好自定义机制。但是好处在于,开发者可以按自己意愿选择传递还是不传递。例如,可以选择在ACTION_MOVE的时候不传递,而在ACTION_UP的时候继续传递给子View,从而实现只屏蔽掉子View的ACTION_MOVE事件。

三、实例讲解

这里引用 android-Ultra-Pull-To-Refresh
源码解析 中的图来进行说明



UltraPullToRefresh是通过重写dispatchTouchEvent()来实现的。可以看到,对于任何MotionEvent,其实都是返回的true。不过由于是自定义传递 机制,因此并不影响。例如,在ACTION_DOWN的时候,先判断是否需要处理该事件,如果需要,则直接进行处理,否则调用子View的dispatchTouchEvent()。其他的原理基本类似,只是在个过程必须细心的判断好处理还是不处理,传递还是不传递,同时,必须告诉Parent自己消费了ACTION_DOWN,才能保证后续事件全部传递过来。


四、总结

继承ViewGroup确实是一个很麻烦的过程,事件处理则是难上加难,以上的技巧只是概括了一些基本的思想。在实践中,则需要根据具体的实现效果去判断自己需要使用哪种方法来实现,这个过程需要细致认真的处理。
以上观点纯属个人总结,有不对之处还望指出,谢谢。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: