浅谈CoordinatorLayout
写在前面
最近这一周空余的时间比较多,然后去重构了一个公司项目里的一个个人中心的页面,原来使用了ListView再加上addHead的方式,然后动态的去控制Head的高度去实现嵌套滑动的效果,因为我的模拟器没有跑起来,所以也没有去录下个GIF来,因为这篇主要说一下CoordinatorLayout的处理嵌套滑动的原理,没有效果图也影响不大。
开始吧
先写出来点大纲吧:
- 为什么要有
CoordinatorLayout CoordinatorLayout是怎么实现嵌套滑动的事件分发的AppBarLayout的一些东西
为什么要有CoordinatorLayout
先来回想一下Android系统的事件分发有什么不足的地方,就是一个view消费了事件,与此同时,其他的view的没有机会去接触到这个事件了。也就是在一个事件的某一时刻,有且只有一个View去相应这个事件。那么当我们要去做一些嵌套滑动的时候,就会有一些不方便。例如需要一个View跟随另一个View滑动,一般就是一个CallBack进行滑动状态的回调。CoordinatorLayout就可以比较优雅的处理这种事件。
CoordinatorLayout是怎么实现嵌套滑动的事件分发的
先说一下两个接口吧,NestedScrollingParent和NestedScrollingChild,这两个接口看名字就比较容易理解他们的作用,就是一个给嵌套滑动的parent实现的,一个是给child实现,在现在的组件中,只有CoordinatorLayout实现了parent,所以下面说到parent就理解成CoordinatorLayout就OK啦,而child这个接口其实方法已经在View这个类里面帮我们实现好了,也就是说想要去成为一个可以嵌套滑动的child,仅仅去实现这个child接口就OK了,其他的View已经帮你写完了。下面还是以RecycleView为例子,它是实现了这个child的接口,还是回到情景里面说吧,说一下到底是怎么传递事件的。
- 在
ReclceView上down ->parent.onStartNestedScroll->遍历有Behavior的直接子view ->child的Behavior.onStartNestedScroll。
这里说一下onStartNestedScroll这个方法是有boolean的返回值,true的意思是要去处理这个事件,同时还会去调用parent.onNestedScrollAccepted-> 遍历有Behavior的直接子view ->child的Behavior.onNestedScrollAccepted.这个方法里面可以做一些view配置的初始化。如果不需要当然可以不去重写。 - 在
RecycleView上move ->dispatchNestedPreScroll(也是child这个接口里面的)->parent.onNestedPreScroll-> 遍历有Behavior的直接子view ->child的Behavior.onNestedPreScroll,同时之后还有一个流程也是在move的时候触发的 ->dispatchNestedScroll(也是child这个接口里面的) ->parent.onNestedScroll-> 遍历有Behavior的直接子view ->child的Behavior.onNestedScroll.。这两个的主要区别的pre那个方法里面可以去处理消费了多少的滑动距离,比如手指滑动了12px,你可以选择把consumed[1]赋值为2,那么head就移动(消费)了2px,剩下的10px就给了下面的recycleview,而在onNestedScroll方法中还有机会去已经消费的和没有消费的距离再进行一次处理。 - 在
RecycleView上面up ->stopNestedScroll(也是child这个接口里面的) ->parent.onStopNestedScroll-> 遍历有Behavior的直接子view ->child的Behavior.onStopNestedScroll。 - 还有两个关于
Fling的方法,就不说了,一个套路。
还有就是再说一下CoordinatorLayout的onInterceptTouchEvent和onTouchEvent,这里贴一下代码吧
|
|
可以看出,每个直接的childview都会接受到拦截事件,即使你的手势不是在这个child上面触发的。
- 还有个方法就是
layoutDependsOn这个方法是在哪里调用的,这个是在onpredraw的时候就调用了,也就是没显示之前就已经开始准备各个view直接的依赖关系。当然内部实现也是在parent里面去便利child来实现的,也就只有parent可以获取到所有的child。
AppBarLayout的一些东西
我觉得AppBarLayout这个组件还是十分重要的,特别是里面的两个Behavior的实现,给了我们很好的参考的例子。具体的还是去看源码吧,太多了要说也是再开一篇。