Android Touch事件的传递
Activity接收Touch事件回调
onTouchEvent
,并且将Touch事件分发给DecorViewDecorView接收到Touch事件后,调用
dispatchTouchEvent
开始分发Touch事件-
ViewGroup根据
onInterceptTouchEvent
判断是否要中断Touch事件传递子View- 如果中断的话,则拦截Touch事件,则会回调
onTouchEvent
- 如果不中断的话,则会调用子View的
dispatchTouchEvent
继续让子View分发Touch事件
- 如果中断的话,则拦截Touch事件,则会回调
直到有子View消费掉了Touch事件,则整个过程就结束了
问题
这种事件传递的结果就会导致以下问题:
一个View把Touch事件消费之后,其他View就无法接收到该事件,也就无法根据这个事件完成与用户的交互
比如:有一个RecyclerView上有一张图和一个按钮,当ListView滑动的时候,希望这张图先往上平移直至移出屏幕,RecyclerView才能开始滑动,并且在滑动时,按钮可以随着滑动的距离进行Scale的变化
实现NestedScroll
希望支持嵌套滑动操作子View的ViewGroup的子类应该实现该接口。实现该接口的的类应该创建一个final的NestedScrollingParentHelper
对象并且将所有的View或者ViewGroup的代理方法都使用它来实现。而View调用嵌套滑动的功能都需要通过ViewGroupCompat
或者ViewParentCompat
来兼容5.0以下以及以上的系统。
NestedScrollingParent
、NestedScrollingChild
、NestedScrollingParentHelper
、NestedScrollingChildHelper
以上的这些类都是用来帮助更快的实现NesedScroll。
NestScroll机制原理
NestedScroll给View与View之间提供了一种关联的机制,可以使得原来只能单独一个View消费的Touch事件变成多个View之间共同协作处理Touch事件
- 当子View接收到Touch事件时,会通过实现了
NestedScrollingParent
接口的ViewParent,告知父View要开始滑动了,而父View此时可以告知实现了NestedScrollingChild
接口的其他子View来共享该事件,并且将其他子View所消耗的X,Y返回给接收事件的子View,供其进行计算
步骤
- 子View实现
NestedScrollingChild
接口,并且在内部初始化一个NestedScrollingChildHelper
对象,将接口中的函数均用Helper对象进行代理 - 父View实现
NestedScrollingParent
接口,并且在内部初始化一个NestedScrollingParentHelper
对象,将接口中的函数均用Helper对象进行代理,同时父View也可以作为NestedScrollingChild存在 - 在子View的
onInterceptTouchEvent
以及onTouchEvent
处理Event事件,并且调用dispatchNestedPreScroll
以及dispatchNestedScroll
方法告知父View处理滑动事件,共同处理手势坐标
参考资料
Experimenting with Nested Scrolling
Android Nested Scrolling