CoordinatorLayout是支持包"com.android.support:design"里很重要的一个控件,继承于FrameLayout,它提供了两个主要用途:
1. 作为APP的顶层布局;
2. 协调子控件的相互作用;
CoordinatorLayout提供了很棒的交互体验,并且也有良好的定制性,可以制作自己想要的交互效果,下面看下一些基本用法。
一. 收缩的ToolBar
可缩放的ToolBar还是很常见的,经常和TabLayout一起使用,比如:bilibili手机客户端。
带Tab的布局,实现ToolBar可收缩:
其中有几个要注意的:
1. CoordinatorLayout作为顶层视图;
2. 在AppBarLayout中放置Toolbar和TabLayout;
3. 设置Toolbar的滚动标志app:layout_scrollFlags="scroll|enterAlways|snap",标志的含义见代码;
4. 给ViewPager设置行为app:layout_behavior="@string/appbar_scrolling_view_behavior",实现与AppBarLayout联动,Behavior是CoordinatorLayout最重要的功能,用来实现子视图的协调功能,Behavior的内容后面再细说;
有了这几个就实现了ToolBar的收缩功能,效果图如下:
二. 滚动折叠CollapsingToolbarLayout
CollapsingToolbarLayout用来实现可折叠的AppBar,它必须作为AppBarLayout的直接子视图,有如下几个特点:
1. 可折叠的Title,在AppBarLayout完全可见是Title最大,Title会随着AppBarLayout的滚动逐渐缩小;
2. 当滚到一个特定值时设置固定内容显示的Drawable;
3. 当滚到一个特定值时设置StatusBar显示的Drawable,需要API21以上,(我在模拟器上试了没效果,不知道真机如何);
4. 带有视差效果地滚动子视图;
5. 子视图可以选择固定在布局中;
6. 不能在运行时手动给ToolBar添加视图;
来看下布局怎么实现:
这里同样有几个需要注意的:
1. CollapsingToolbarLayout的几个属性,包括滚动视差模式和滚动视差系数,看代码;
2. 在CollapsingToolbarLayout设置了exitUntilCollapsed滚动标志,我们前面说过了会根据minHeight来设置最终固定的值,但我们这里并没有显示设置minHeight属性,其实CollapsingToolbarLayout会去查找子视图中的ToolBar并设置minHeight为它的高度;
3. FloatingActionButton设置两个属性layout_anchor和layout_anchorGravity,会去关联指定的视图和相对该视图的空间位置,如上关联视图为AppBar,CoordinatorLayout会处理他们两个之间的交互关系。还有一个要提的就是,FloatingActionButton的空间位置并不仅仅只是由设置的layout_anchorGravity决定,需要和所关联的视图的Gravity共同决定;
同样来看下效果:
三. Behavior
不知道你有没有注意到,前面两个例子中FloatingActionButton的变化,第一个是Snackbar出现时上移动画,第二个是随AppBar滚动的消失动画。我们前面也说了在CoordinatorLayout中要实现动画交互效果需要设置Behavior,但我们并没有给FloatingActionButton设置Behavior为什么它还会有动画呢?有这个疑问去看下源码就知道了,我们来看下FloatingActionButton的部分源码实现:
@CoordinatorLayout.DefaultBehavior(FloatingActionButton.Behavior.class)
public class FloatingActionButton extends VisibilityAwareImageButton {
// 略.......
/**
* Behavior designed for use with {@link FloatingActionButton} instances. It's main function
* is to move {@link FloatingActionButton} views so that any displayed {@link Snackbar}s do
* not cover them.
*/
public static class Behavior extends CoordinatorLayout.Behavior {
// We only support the FAB <> Snackbar shift movement on Honeycomb and above. This is
// because we can use view translation properties which greatly simplifies the code.
private static final boolean SNACKBAR_BEHAVIOR_ENABLED = Build.VERSION.SDK_INT >= 11;
private ValueAnimatorCompat mFabTranslationYAnimator;
private float mFabTranslationY;
private Rect mTmpRect;
@Override
public boolean layoutDependsOn(CoordinatorLayout parent,
FloatingActionButton child, View dependency) {
// We're dependent on all SnackbarLayouts (if enabled)
return SNACKBAR_BEHAVIOR_ENABLED && dependency instanceof Snackbar.SnackbarLayout;
}
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionButton child,
View dependency) {
if (dependency instanceof Snackbar.SnackbarLayout) {
updateFabTranslationForSnackbar(parent, child, dependency);
} else if (dependency instanceof AppBarLayout) {
// If we're depending on an AppBarLayout we will show/hide it automatically
// if the FAB is anchored to the AppBarLayout
updateFabVisibility(parent, (AppBarLayout) dependency, child);
}
return false;
}
@Override
public void onDependentViewRemoved(CoordinatorLayout parent, FloatingActionButton child,
View dependency) {
if (dependency instanceof Snackbar.SnackbarLayout) {
updateFabTranslationForSnackbar(parent, child, dependency);
}
}
private boolean updateFabVisibility(CoordinatorLayout parent,
AppBarLayout appBarLayout, FloatingActionButton child) {
// 实现FloatingActionButton的消失和显示动画
}
private void updateFabTranslationForSnackbar(CoordinatorLayout parent,
final FloatingActionButton fab, View snackbar) {
// 实现FloatingActionButton的移动动画
}
// 略.......
}
}
看到开头的
@CoordinatorLayout.DefaultBehavior(FloatingActionButton.Behavior.class)就大概能猜到
FloatingActionButton的默认Behavior为FloatingActionButton.Behavior这个类所设定。我们来看下FloatingActionButton.Behavior里面都做了什么,在这之前先来了解下这几个方法是来做什么的:
1. layoutDependsOn():用来确定关联的视图;
2. onDependentViewChanged():当关联视图发生改变时回调接口;
3. onDependentViewRemoved():关联视图移除时回调接口;
知道了这几个方法是做什么的看下代码应该也就知道FloatingActionButton的交互动画是怎么来的,但你有没有注意到在layoutDependsOn()方法中只有对Snackbar进行判断,并没有对AppBarLayout进行处理,但它为什么还能和AppBarLayout进行联动呢?有这个想法就没错了,你可以试着改下第二个例子中的FloatingActionButton的layout_anchor属性,让它不指定为AppBarLayout,而指定为头部显示的图片,你就会发现FloatingActionButton不会消失啦~所以大概就能得出个结论,Behavior所关联的视图还包括layout_anchor属性指定的视图。
至于动画效果怎么来的,具体去看下updateFabVisibility()和updateFabTranslationForSnackbar()这两个方法就知道了。
CoordinatorLayout的基本介绍就到这里了,自定义Behavior的内容:
CoordinatorLayout自定义Behavior的运用
源代码:CoordinatorLayoutSample