Android事件分发机制:Activity--ViewGroup--View
Activity dispatch到ViewGroup,通过OnInterceptTouchEvent 判断是否拦截,如果不拦截则分发到View的OnTouchEvent。然后开始事件消费流程
事件消费:View--ViewGroup--Activity
View的OnTouchEvent如果return true 则代表事件由view消费了,否则返回给ViewGroup的onTouchEvent,如果ViewGroup还不消费则会返回给Activity。
传统的处理嵌套滑动的方式有缺陷:
当双层滚动嵌套时候,我们会通过一系列判断,通过外部拦截和内部拦截来处理事件分发逻辑。但是一个手势包含Action.Down Activon.MOVE.. Activo.Cancle/Up 组成。 当一个手势通过事件拦截处理后,比如Action.Down 分发给了View 后续一些列事件都会分发给View。如果想出发下次事件拦截,则需要重新出发一次手势。反应到界面上,就是用户在两个嵌套的组件件无法做到一个手势流畅的滑动(因为一个手势只能在一个地方消费)。因此Google 推出了嵌套滑动接口,把一个手势拆开分发,让嵌套组件可以无缝滑动。
嵌套滑动接口
NestedScrollingChild
NestedScrollingParent
接口的方法我们可以调用Help类来实现功能:
NestedScrollingChildHelper
NestedScrollingParentHelper
调用help类同名方法:
child和parent调用关系
事件从child 的OnTouchEvent 开始消费,所以我们的逻辑从OnTouchEvent写。
Action_Down
调用helper的startNestedScroll()
一层层遍历parent,找到支持NesteParent接口的父View,调用parent的onStartNestedScroll
和onNestedScrollAccepted。parent onStartNestedScroll一般返回true,如果返回false
parent 就不滑动了。
helper.onNestedScrollAccepted 会记录滑动轴的一些信息。到这里Action.Down事件的交互就结束。
Action_Move
dispatchNestedPreScroll 调用help的同名方法,最终调用parent的 onNestedPreScroll。 consumed是个数组第一个 元素代表Parent x轴滚动距离,第二个元素代表Parent y轴滚动距离。 最终parent处理完滑动后,会把滑动距离给到child。
Parent根据需要判断自己的滑动距离,自己通过scrollBy消费,然后调用consumed 把消费量返回给child
stopNestedScroll 和 dispatchNestedFling 过程也是这样的。
总结: NestedScrollingParent 和 NestedScrollingChild 是两个接口,中间通过Help类进行交互。根据自己业务逻辑来判断滑动是由Parent 还是 Child来消费,从而达到把一个手势分开来响应的效果。