Android 优化交互 —— CoordinatorLayout 与 Behavior

6

前言

如果你已经很时髦的用上了AppBarTabLayoutFloatActionButton,以及Snackbar的话,我想你多多少少肯定知道CoordinatorLayout这个东西。 它的神秘感来自于在布局文件 (xml) 和代码调用上完全看不出和其他组件任何的耦合,却能做出一些神奇酷炫的交互效果。

clipboard.png

对,没错,今天我们就着重讲一下CoordinatorLayout 是如何工作的,或者说,是如何让别的组件亲密无间的“合作”起来的(以及,顺便会打下一点点的广告)。

CoordinatorLayout 到底是干嘛的?

顾名思义,CoordinatorLayout专注于把它的子View连接起来,使他们之间相互很好的配合。

那么既然是合作,CoordinatorLayout的职责充当了一个第三方的角色,通知各个子View之间状态的变换,的确,它也只干了这么一件事,非常纯洁&纯粹。

那么既然有通知,一定需要媒介,总不能把子View全部改造成适合现在这种模式的模样吧?这样也太不OO了,这里的介质就是BehaviorBehaviorCoordinatorLayout用来和各个子View通信用的代理类。

来自Behavior的代理 —— 布局

CoordinatorLayout通过Behavior控制子类

注意箭头的走向,CoordinatorLayout是通过Behavior去控制子视图,也就代表Behavior的数据传导基本上是单向的。当CoordinatorLayout需要进行measurelayout的时候,都会通过behavior询问子视图,是否需要进行相应的操作,如果不需要,就进行默认的行为,我们来看下onLayoutChildonMeasureChild两个再熟悉不过的行为。

clipboard.png

clipboard.png

可以看@return的说明,如果Behavior处理了相关的操作,那么就会覆盖CoordinatorLayout默认的行为(其实它的默认行为和FrameLayout简直一模一样)

这一节简单的说了CoordinatorLayout如何通过Behavior来控制子View的布局相关的行为,接下来我们看看重点的交互部分。

来自Behavior的代理 —— 触摸事件之普通流程

CoordinatorLayout的功能当然不仅仅是通过Behavior来控制子视图的布局,控制触摸的流程才是大头。

首先我们知道,控制触摸事件,一般有2个:

  1. onInterceptTouchEvent.

  2. onTouchEvent

这里不解释他们之间的区别,我们看到在Behavior中也有这么两个方法。

clipboard.png

clipboard.png

如果你的View所拥有的Behavior 处理了相关的事件,那么接下去发到CoordinatorLayout上的触摸事件就会像正常流程一样发到这个Behavior中。

我们终于可以实现在不子类化View的情况下,重写它的触摸事件啦。

来自Behavior的代理 —— 触摸事件之 NestedScrolling

这才是重点中的重点啊!!
首先,我们来睁大眼睛看!

clipboard.png

好,可以看见CoordinatorLayout是实现了NestedScrollingParent接口的,也就是说,要用到这个特性的话,默认不实现NestedScrollingChild接口 (pre Lollipop) 且不调用dispatchNestedScroll相关接口的View靠一边去! 【ListView 哭晕在厕所】

CoordinatorLayout正是从NestedScrollingParent相关的接口中,获取到嵌套滚动相关的参数,再通过Behavior传到各个子View中,包含BehaviorView这时候才成为真正处理嵌套滚动的对象,消费掉一些滚动参数后,再把消费掉的数值传回到发生触摸事件的View中,达到交互的目的。

clipboard.png

consumed这个数组可以在View0中获取到,表示的意思是它的NestedScrollParent消费了多少的滑动量,意味着它能使用的滑动量要减去数组里的值。
这样产生滑动的View就通过CoordinatorLayout和 其他的ViewBehavior 产生了交互,我们可以在Behavior 中给View生成一些位置的偏移量,达到视图上移动的效果。

来自Behavior的代理 —— layoutDependency

布局依赖,这也是个很重要的东西,比如FAB的位置需要在Snackbar上边,需要依赖它来操作。
主要有2个接口(用的比较少的暂时忽略):

  1. layoutDependsOn

  2. onLayoutDependencyChanged

第二个接口通常在onPreDraw或者onNestedScroll系列的回调中 最后进行调用,注意:它并不是在onLayout过程中回调的

第一个很显然是告诉CoordinatorLayout,一个View是否依赖于另一个View。

第二个是CoordinatorLayout发现存在依赖的时候,把被依赖方回调给依赖方因为这时候,layout已经完成,我们可以获取被依赖方的所有布局信息,根据布局信息,使用offset来决定依赖方的一些位置;同时在这个时候,你也可以调用requestLayout进行重新布局。

最后的最后

好了, Guang Gao Time:

SegmentFault for Android 新版在奋力开发中,带着对Material Design的执着,强势归来!

图片描述

欢迎关注我Github 以及 @Gemini


如果觉得我的文章对你有用,请随意赞赏

你可能感兴趣的

18 条评论
慢慢学 · 2016年04月28日

接的比较生硬,如果以前接触过协调布局可能知道你在说什么,没接触过的估计很难看懂

+2 回复

慢慢学 · 2016年04月28日

写的有些乱

+1 回复

WatsonYao · 2016年04月28日

Material G+ ~

+1 回复

oopser · 2016年05月05日

厉害

+1 回复

Gemini 作者 · 2016年04月28日

咦? 不会吧… 那应该怎么样的结构比较好? 我是由浅入深的结构了

回复

Gemini 作者 · 2016年04月28日

额……我文章第一句话就把你说的这个群体排除掉了…要是再从概念解释的话篇幅真没法控制啦

回复

shangguansb · 2016年04月28日

大神 我觉得seg的个人信息页面有点太单调了,为此我利用MTdesign设计了一个个人信息页面,您请看https://github.com/shangguansb/CoordinatorLayoutUserInfoShowPage

回复

zht7216 · 2016年05月09日

非常受用,顺便问一下楼主的流程图是用什么软件画的?

回复

x3daniel · 2016年05月24日

请问下底部的BottomBar怎么配合CoordinatorLayout使用?能贴下整个布局的控件结构嘛?

回复

阿木amu · 2016年05月31日

这个系列匆匆看了一下,还没有完全理解。想做个Appbarlayout那样的View,用来包含需要滚动的HeaderView,下面放一个ViewPager。HeaderView作为ViewPager公共的头部。需要跟着ViewPager里面的内容滚动同时滚出或者滚入。有推荐的实现吗?或者给点指点吧。

回复

Gemini 作者 · 2016年06月01日

这个可以直接用scrollview套viewpager吧?或者我理解有误?

回复

阿木amu · 2016年06月01日

直接ScrollView套用ViewPager,ViewPager显示不出来。我的场景是ViewPager里面是多个Fragment,Fragment里面是RecyclerView或者ListView之类的,滚动时需要整个界面滚动而不是只在ViewPager内部滚动。

回复

Gemini 作者 · 2016年06月01日

我想你ViewPager 高度一定是设置了wrap_content 设置个固定高度你试试

回复

阿木amu · 2016年06月03日

wrap_content和match_parent都不显示。固定高度可以显示,但固定高度后ViewPager只在内部滚动,直到滚动到最后才能带动HeaderView滚动。其实就是想要这篇文章提到的效果:https://segmentfault.com/a/1190000005147568 。 又不想要AppbarLayout和CollapsingToolbar除了滚动之外的其他特性。

回复

皇马船长 · 2016年08月16日

有这种上滑导航栏隐藏的demo吗?

回复

0

同求啊啊啊啊啊啊啊

情随事迁 · 2017年03月07日
兰_亦辛 · 2016年09月02日

同问

回复

matrixxun · 2017年07月25日

表达能力实在是。。。不想吐槽了

回复

载入中...