此篇文章需要用到之前的知识点,即我之前写的这两篇博客
事件分发机制原理分析
NestedScrolling机制原理分析
一.CoordinatorLayout基本介绍
1.使用场景
一般作为应用的顶层布局,同时也作为一个管理容器,管理与子view
或者 子view
之间的交互。那么都具体管理啥呢?可以分成四个部分
2.作用
- ①处理子控件之间依赖下的交互
- ②处理子控件之间的嵌套滑动
- ③处理子控件的测量与布局
- ④处理子控件的事件拦截与响应
以上四个功能,都建立于CoordainatorLayout
中提供的一个叫做Behavior
的**“ 插件”**之上。Behavior内部也提供了相应方法来对应这四个不同的功能。那么都有哪些方法呢?
3.Behavior中的常用方法
4.为什么把这些方法都放到Behavior
中呢?
答案:解耦。当用的时候就集成进去,不用的时候就remove
。即可插拔。
- 在这里可以把
CoordinatorLayout
比喻成Android Studio,把子View
比喻成我们的项目。我们知道,AS
可以使用Plugins
为项目引入各种插件,从而实现不同的功能,同样的道理,CoordinatorLayout
可以使用Behavior
为子View
引入各种行为。Behavior
也是**“可插拔”**
二.CoordinatorLayout四个功能的原理
1.CoordinatorLayout下依赖交互功能原理(观察者模式)
当CoordainatorLayout
中子控件depandency
的位置、大小等发生改变的时候,那么在CoordainatorLayout
内部会通知所有依赖depandency
的控件,并调用对应声明的Behavior
,告知其依赖的depandency
发生改变。
- 那么如何判断依赖是哪个
View
呢?
layoutDependsOn
方法 - 接受到通知后如何处理呢?
onDependentViewChanged
/onDependentViewRemoved
方法
原理图
dependency
也是一个child
,和child1
、child2
在布局上可以是并列的。后面我们把dependency
统一称为DepandedView
2.CoordinatorLayout内部嵌套滑动原理
CoordinatorLayout
实现了NestedScrollingParent2
接口。所以当事件(scroll
或fling
)产生后,内部实现了NestedScrollingChild
接口的子控件会将事件传递给CoordinatorLayout
,CoordinatorLayout
又会将事件传递给所有的Behavior
。然后在Behavior
中实现子控件的嵌套滑动。
具体流程图
相对于NestedScrolling
机制(参与角色只有子控件和父控件),CoordainatorLayout
中的交互角色玩出了新高度,在CoordainatorLayout
下的子控件可以与多个兄弟控件进行交互。即从1:1
变成了1:N
3.CoordinatorLayout子控件的测量与布局
在特殊的情况下,如子控件需要处理宽高和布局的时候,那么交由Behavior
内部的onMeasureChild
与onLayoutChild
方法来进行处理
4.CoordinatorLayout子控件的事件拦截与响应
对于事件的拦截与处理,如果子控件需要拦截并消耗事件,那么交由给Behavior
内部的onInterceptTouchEvent
与onTouchEvent
方法进行处理
三.源码分析CoordinatorLayout子控件依赖交互功能原理
由于View
的生命周期的开始是在onAttachedToWindow
方法中,所以我们进入此方法寻找
1.我们在CoordinatorLayout
类中找到onAttachedToWindow
方法
发现它调用getViewTreeObserver
,获得ViewTreeObserver
,然后调用了addOnPreDrawListener
- 关于
ViewTreeObserver
:
ViewTreeObserver
注册一个观察者来监听视图树,当视图树的布局、视图树的焦点、视图树将要绘制、视图树滚动等发生改变时,ViewTreeObserver
都会收到通知,ViewTreeObserver
不能被实例化,可以调用View.getViewTreeObserver
()来获得 - 关于
dispatchOnPreDraw
:通知观察者绘制即将开始,如果其中的某个观察者返回true
,那么绘制将会取消,并且重新安排绘制,如果想在View Layout
或Viewhierarchy
还未依附到Window
时,或者在View
处于GONE
状态时强制绘制,可以手动调用这个方法
2.接下来我们看一下它添加的监听者是个啥,追踪addOnPreDrawListener
,找到OnPreDrawListener
类
当View
发生变化的时候会调用onChildViewsChanged
方法。
3.我们追踪onChildViewsChanged
它有一个类型,即type
也就是DispatchChangeEvent
注解。我们点进去看