当前位置: 首页 > 科技观察

AndroidTouchEvents(注释)

时间:2023-03-13 04:36:45 科技观察

网上类似标题的文章不要多说。我曾经以为我已经掌握了它。直到最近在使用的时候发现了一个问题,我才意识到之前我并没有真正理解它,于是写在下一篇笔记中,事件分发的逻辑依赖于ACTION_DOWN。同时需要注意的是,ACTION_MOVE和ACTION_UP的流程与ACTION_DOWN的流程并不完全相同。下图是ACTION_DOWN手势的处理逻辑图。之前,我对手势处理的概念只停留在这里,我也错误地认为ACTION_MOVE和ACTION_UP的逻辑应该是这样的(就我身边的情况而言,不止我这么想)。这里我们以ViewGroup为例进行总结(注意,为了方便理解,我只分析了ViewGroup,activity和View略有不同)dispatchTouchEvent如果返回true就可以消费事件,然后自己消费事件并终止传递;如果返回false,如果事件没有被消费,则由父级的onTouchEvent处理;如果返回super,则不会消费事件,事件会被派发到onInterceptTouchEvent处理。onInterceptTouchEvent不能消费事件。如果返回true,事件会派发到自己的onTouchEvent中去处理;如果返回false/super,事件会被派发到child的dispatchTouchEvent处理;onTouchEvent可以消费事件。如果返回true,则事件将被自己消费,终止传输。;如果返回false/super,将事件派发给父级的onTouchEvent处理;可以看到,最终消费事件的地方只有两个,dispatchTouchEvent和onTouchEvent返回true的时候,和返回false的时候,都是把事件交给上层的onTouchEvent处理。一个在onInterceptTouchEvent之前,一个在onInterceptTouchEvent之后,onInterceptTouchEvent只是把事件分流,就构成了这个android事件传递图。ACTION_MOVE和ACTION_UP的总结在默认返回super的情况下,哪一层的onTouchEvent返回true,那一层的onTouchEvent会收到ACTION_MOVE和ACTION_UP,同级及以上的dispatchTouchEvent和onInterceptTouchEvent都能收到ACTION_MOVE和ACTION_UP,如下图从上图我们可以看出最终能收到ACTION_MOVE和ACTION_UP的onTouchEvent只能有一个。即使你的上层onInterceptTouchEvent为ACTION_MOVE返回true,也只会向上层分发ACTION_MOVE事件,子View不会接收到ACTION_MOVE事件,也就是说当一个View在onTouchEvent中ACTION_DOWN返回true时,它的ACTION_MOVE和ACTION_UP事件其实不管返回什么结果都是一样的,因为这里已经分发了ACTION_MOVE事件,即使返回false,上层还是接受的!不!到达的!(这个概念和我之前的三观完全不符,当然你觉得不对可以反驳我,我一开始是不相信的)requestDisallowInterceptTouchEvent的使用在在手势处理中,我们也可以使用requestDisallowInterceptTouchEvent方法来拒绝onInterceptTouchEvent拦截事件。对于一些GroupView,会在onInterceptTouchEvent事件中拦截ACTION_MOVE事件,比如ListView、ScrollView等,此时childView无法获取到ACTION_MOVE事件(普通ScrollView嵌套ViewPager,ViewPager不能滑动),除了重写GroupView的onInterceptTouchEvent方法,我们也可以重写ChildView的dispatchTouchEvent方法来解决,首先不管GroupView多么霸道,默认情况下是不会在onInterceptTouchEvent的ACTION_DOWN事件中返回true的,因为这样会导致childView没有机会获取完全没有手势。然后,childView可以在dispatchTouchEvent方法中接收ACTION_DOWN事件。这个时候我们调用parent的requestDisallowInterceptTouchEvent方法,设置为true,通知GroupView不要拦截我的事件,那么接下来,本应该被GroupView拦截的ACTION_MOVE事件就会绕过GroupView的onInterceptTouchEvent方法,直接下载它到childView的dispatchTouchEvent。值得注意的是,dispatchTouchEvent中getParent().requestDisallowInterceptTouchEvent(false)的效果与returnfalse不同。当GroupView.requestDisallowInterceptTouchEvent(true)时,onTouchEvent方法是不会接收到任何事件的,所以此时如果在ChildView的dispatchTouchEvent方法中返回false,其实效果和returntrue是一样的。只有当GroupView.requestDisallowInterceptTouchEvent(false)时,手势才会再次交给GroupView。所以,这个时候,如果只想在ChildView中消费某类ACTION_MOVE事件(比如水平滑动),就需要调用getParent().requestDisallowInterceptTouchEvent(false),而不是返回false,如下图:另外,网上很多人会在ACTION_UP的时候调用getParent().requestDisallowInterceptTouchEvent(false),但是没有必要,因为当收到ACTION_DOWN时,GroupView会默认将requestDisallowInterceptTouchEvent重置为false。