CoordinatorLayout 你不得不了解一下


版权声明:

本公众号发布的所有文章,均属于原创,版权归本公众号所有。

一、前言

Design Support Library (以下简称 DSL)是 Google 发布的一个全新的兼容函数库,它可以在 Android 2.1 (Api level 7)及以上的设备中,实现 Material Design 的效果,这个函数库同时也提供了一系列控件。

DSL 中提供的控件,有时间都会介绍到。其实掌握 DLS 里添加的控件,可能在实际工作中真的没什么用得着的地方,毕竟 App 长什么样子,UI、UE 来决定,代码层面的事情,才是我们需要负责的。而真的去研究 DSL 里的一些设计,你会发现 DSL 设计的很精妙,弄清楚它实现的原理,对你实现一些『奇葩』效果,会有很大帮助的。

今天介绍一个在 DSL 中承担一个万金油角色的控件 , CoordinatorLayout(以下简称CL) ,在 DSL 中,提供的很多效果,都是依赖 CoordinatorLayout 来实现的。而 CL 本身也非常的复杂,承载各种功能。本文在写着写着我发现并不能通过一篇文章完全写清楚 CL 。还好 CL 因为功能强大,所以可以通过一些方法的组合,实现部分功能,而 DSL 中,一般控件也只是用到了 CL 的部分功能而已。所以我决定进行拆分,一篇一篇的写。

在使用 DSL 之前,需要在 build.gradle 文件中,添加对其的依赖:

compile 'com.android.support:design:25.3.0'

二、CoordinatorLayout

CL 是一个直接继承自 ViewGroup 并实现 NestedScrollingParent 接口的控件,它主要的功能,就是协调其内部的各个子控件之间的状态关系。

简单来说,如果需要在布局中协调多个 View 进行互动,例如:移动、动画等等。在以前,是需要同时对这些 View 进行操作并响应各自的状态的,而有了 CL ,这些它都帮我们实现好了交互的接口,我们只需要去关心具体的细节。

在 DSL 中,很多地方都用到了 CL,举几个例子:

  1. SnackBar 出现的时候,浮动操作按钮(FAB)上移。
  2. 配合 ToolBar ,实现一个可伸缩头部 Title。
  3. 配合 AppBarLayout,实现一个具体的是视差动画的效果。

这些例子的效果,在 MD 的设计中,应该是随处可见的。

虽然这里讲的是 CL ,但是其实对于开发者而言,我们是不会和 CL 直接打交道的,而 CL 透出来的接口 Behavior 才是我们需要关心和实现的。

CL 和 Behavior 之间进行交互,将其内需要被协调的 View ,之间的变动,通过 Behavior 传递出来,开发者只需要针对 Behavior 中定义好的接口方法,进行对应的实现即可。

三、CoordinatorLayout 能干什么

虽然 CL 可以实现的效果很多,但是我们先从最简单的来看,一个 View 依赖另外一个 View 的移动而移动。

类似上面的效果,当我们移动蓝色方块的时候,红色方块也跟着移动,这样红色方块可以一直保持和蓝色方块相同的距离,而如果接近边界,红色方块换位置,一致保持在蓝色方块的两边。

在以前,我们需要如何实现这样的一个效果?

首先需要监听蓝色方块的移动,然后在移动的时候,对外暴露一个接口,让红色方块也可以获取到蓝色方块移动的距离,然后跟随着进行移动。

而现在,只需要使用 CL ,实现一个我们需要的 Behavior 即可。

在讲具体实现之前,有一些 CL 相关的概念需要提前讲讲。

CL 和 Behavior 的通信模式有一点像设计模式里的观察者模式。对于 CL 内部的子 View 而言,都可以是被观察者,而 CL 观察这些被观察的 View 的行为,例如:移动、滚动等等,当观察到这些被观察的View的行为的时候,再通过 Behavior 通知给需要观察它状态的 View,被观察的View的变动情况。

说的有点乱,举个例子:就像警匪片里,卧底的身份一样,在观察到土匪有行动的时候,通知给警方,警方到底是收线抓人还是放长线钓大鱼,就是警方内部自己决定的了。

而在 Behavior 中,存在的角色就是 dependency 和 child 。如果 child 依赖 dependency 的行为来触发某些对应动作,那么他们之间就建立了依赖的关系。

四、如何实现联动效果

1、先熟悉一下 API

首先,因为 Behavior 是一个泛型接口,并且被限定了只能是 View 类型的子类,这个泛型定义的 View,就是我们需要前面介绍的 child 角色。

而我们主要是对 Behavior 进行进行实现,主要需要用到它的两个方法。

  1. boolean layoutDependsOn(parent,child,dependency):判断 child 是否依赖 dependency。
  2. boolean onDependentViewChange(parent,child,dependency):如果layoutDependsOn 中返回true,在此方法中 child 实现根据依赖的 dependency 的变动情况变动 child。

和前面的描述一致,首先 Behavior 会通过 layoutDependsOn 方法,确定当前 child 是否和 dependency 有依赖关系,如果有,就把 dependency 的变动 ,传递给 child,否者就直接过滤掉。

layoutDependesOn 的完整签名如下:

onDependentViewChange 的完整签名如下:

2、开始编写 Behavior

既然已经了解了,在 CL 中,实现联动效果需要用到的 API 。那么接下来我们就实现一个 Behavior。

这里定义一个 TouchView 来实现触摸跟随移动的效果,代码非常的简单,这里就不贴了。再使用一个TetxView 来依赖 TouchView。然后我们就可以开始实现 Behavior 了。

和之前描述一样,首先通过 layoutDependsOn() 确定依赖关系,然后在 onDependentView() 方法内,根据依赖的变动,变动 child 即可。

在这里,首先确定 child 在 dependency 的方向,是左还是右,然后再计算出 child 最终的位置,进行变动。

3、作用在布局中

实现好 Behavior 就可以在布局中,通过 app:layout_behavior 属性,为child 角色,定义它的 Behavior 。

最后达到的效果,就是本文前面给出的 gif 效果,这里就不重复贴图了。

五、总结

虽然 CL 可以实现的功能非常的多,但是我们也需要由浅入深的去理解它,本文只是讲解了它最简单的使用方式,具体需要实现什么功能,是否用 CL 会比较合适,都需要看实际的效果来觉得。

最后,如果觉得不错,赞一个吧。