前言
了解流程和具备的能力
- 事件的种类和手势
- view的体系结构和事件分发
- view和viewgroup的分发流程
- 解决滑动冲突
- 代码分析
注:本文只对单点触摸进行处理,多点触摸我们不进行讨论
1、事件的种类和手势、了解单点触摸
图1
2、view的体系结构和事件分发
首先我们需要了解view与viewgroup之间的关系
(1)viewgroup继承了view(从代码角度而言)
(2)viewgroup是view的父亲(从运行时角度而言)
而我们处理嵌套滑动的时候,主要是基于第二点,也就是运行时的角度。
以下两张图就能正确表面,运行时view与viewgroup之间的关系
图2
图3
我们通过源码可以得知,事件处理函数主要包括三个:dispatchTouchEvent(事件分发)、onInterceptTouchEvent(事件拦截)、onTouchEvent(事件消费)
下图我们可以清楚的知道,事件分发的流程
图4
当我们手指触摸到屏幕的时候,activity获取事件,传递给decorview,decorview通过dispatchTouchEvent(事件分发)将事件分发给LinearLayout如图2所示
那么该LinearLayout如果想将事件进行拦截,那么就要执行onInterceptTouchEvent(事件拦截),如果不执行,那么事件还会一级一级的往下走,直到被拦截或者到最底层然后执行onTouchEvent,这就是事件分发
但是子view会有所谓的“尚方宝剑”,我们知道事件冲突会有内部拦截和外部拦截,那么内部是如何拦截的呢?
如下图所示,在viewgroup里面的dispatchTouchEvent方法里面,有这样一段代码,那么他的作用是什么呢?
通过上面的学习,我们知道事件是一层一层往下传递的,那么父view很可能会将事件进行拦截,这样来说对子view是不公平的。因此子view可以通过内部拦截,请求父view不要拦截事件,告诉父view这个事件是我的,那么这个标志位就是下图代码disallowIntercept变量。
图5
3、View和ViewGroup的分发流程
事件分发简易流程
首先判断是否有子view拦截,也就是上面所说的尚方宝剑,如果子view不需要,则判断自身是否需要拦截。
图6
事件分发进阶流程
图7
4、解决滑动冲突
图8
图8是整个手指在屏幕滑动的时候所触发的各个函数以及流程。我们直到,嵌套滑动是包含两个角色的,一个是父view,一个子view,那么父view是需要实现NestedScrollingParent,子view是需要实现NestedScrollingChild
这也是为什么我们后面的代码用到的是NestedScrollView,而不是ScrollView。
图示我们把view当成界面,NestedScrollingChild当做recyclerView,NestedScrollingParent当做是NestedScrollView,这样方便理解一点,因为淘宝首页二级联动就是这样嵌套的,一下也以这个为思路。
当点击view之后,recyclerView执行4、5、6步,找到自己的父view——NestedScrollView,然后滑动的时候执行7、8步,获取到父view是否需要滑动,如果需要滑动则只滑动父view就可以了。
但是在第8步的时候,父view会直接把事件传递给他自己的父view,也就是事件会传递到NestedScrollView的父亲。因为NestedScrollView实现了NestedScrollingParent接口,同时也实现了NestedScrollingChild接口
所以他会跟recyclerView一样,把事件传递给他的父view,但是他的父view实际上是一个linearLayout了,这不是我们需要的,因此我们需要重写一个NestedScrollView,重写他的onNestedPreScroll方法。
Fling即为惯性滑动,通过速度算出距离。