Android事件分发

来源:互联网 发布:h3c配置vlan多个端口 编辑:程序博客网 时间:2024/06/01 09:38

Android事件分发,其实就是从RootView开始,以树形结构逐层向子View分发事件,直到某个View表示需要处理该事件,其父View则将其记录下来,之后的事件都传递到该View,若子View不需要此事件,则返回给它的父 View进行处理,而在分发的过程中,父 View可以主动选择是否拦截该事件直接自己处理。

涉及的方法主要有:

1.dispatchTouchEvent(MotionEvent ev) 事件分发

2.onInterceptTouchEvent(MotionEvent ev)   事件拦截

3.onTouchEvent(MotionEvent ev)   事件处理

因为Activity的事件分发实质上也是通过其内部的ViewGroup进行分发的,所以讨论得对象只需要分为View与ViewGroup。

一.对于View

在Android的整个View体系中,View(此处的View指的具体某一个控件)的角色就像是树的叶子,所以没有事件分发,没有事件拦截,需要考虑的就是是否消费这个事件。

View的dispatchTouchEvent 实际上返回的就是onTouchEvent(event),可以理解为它本身没有子View,所谓的分发也就是分发给自己,至于是否要处理这个事件(只限于Acition_Down事件),则是由onTouchEvent(event)的返回值来决定。若onTouchEvent(event)返回true,则消费这个事件,便表示它是真正要处理这次请求的View,之后的事件(Move,Up)都回由该View来处理,若返回的false,则说明该View不处理该事件,将由其父View决定是否处理该事件。

对于View 来说,更应该关注的是onTouchEvent(event) onTouchListener.onTouch() 以及OnClickListener.onClick等设置回调监听方法的顺序。

二.对于ViewGroup

这里的ViewGroup只考虑有子View的情况,没有子View的ViewGroup可以当作View来处理。有子View的存在,要考虑到事件的分发dispatchTouchEvent,事件拦截onInterceptTouchEvent以及事件处理onTouchEvent。

dispatchTouchEvent :只负责事件的分发,当返回值是true的时候则会停止事件的分发,若返回fasle则由其父View的onTouchEvent处理该事件,若返回super.dispatchTouchEvent则会分发给onInterceptTouchEvent.

onInterceptTouchEvent:决定当前的ViewGroup是否拦截该事件,若返回true则将事件交给onTouchEvent处理,若返回false则将事件继续分发给子View。

onTouchEvent:与View相同,根据返回值决定是否消费该事件 .

常见的事件冲突:

问题一:ListView 添加ViewPager 作为header

解决思路:重写ViewPager,根据水平滑动距离与竖直滑动距离来判断滑动意图,若是水平滑动,则通过getParent().requestDisallowInterceptTouchEvent(true)让父控件不拦截ViewPager的事件,反之通过getParent().requestDisallowInterceptTouchEvent(false)让父控件处理该事件。

问题二:ScrollView嵌套ViewPager

解决思路:

1.重写ViewPager,与问题一相同

2.重写ScrollView,在onInterceptTouchEvent()中通过判断x与y方向的值来决定返回值

问题三:ViewPager嵌套ViewPager

解决思路:此场景也就是外部ViewPager可滑动,而内嵌的ViewPager无法滑动,解决方法可通过重写内嵌的ViewPager,利用requestDisallowInterceptTouchEvent来请求父控件不要屏蔽事件,可判断首末页将事件交给父控件处理,进行优化。

总结:此类问题的根本就是考虑应该将事件给谁进行处理,根据事件分发的机制,总是由父控件向子控件分发,因此也可以说解决的思路在于考虑父控件是否应该拦截该事件,从源码来看,父控件是否拦截事件由disallowIntercept(通过此方法设置requestDisallowInterceptTouchEvent())与onInterceptTouchEvent()的返回值来确定,所以一般解决此类型的事件冲突根据手势方向和触摸点坐标来判断,实际的操作就是重写子view或者父view。

0 0
原创粉丝点击