今天想总结一下Material Design的两个控件CoordinatorLayout+AppBarLayout,主要是AppBarLayout。结合着两个控件,可以实现一些炫酷的效果。如下:
可以看到我们的Toolbar会随着我们的RecyclerView 滚动而发生隐藏或者展开。效果还是比较炫的!
我们查看源码,发现APPBarLayout 继承 LinearLayout,并且是一个竖直方向上的LinearLayout,其实它最主要的作用就是当某个可滚动的View发生滚动时(例如RecyclerView 发生滚动),其内部子View如果跟着一起发生动作,这动作系统为我们提供了几种。
请注意:上面提到的某个可滚动View,可以理解为某个ScrollView,ListView等。怎么理解上面的话呢?就是说,当某个ScrollView发生滚动时,你可以定制你的“顶部栏”应该执行哪些动作(如跟着一起滚动、保持不动等等)。那某个可移动的View到底是哪个可移动的View呢?这是由你自己指定的!如何指定,我们后面说。
我们先来看下刚刚的例子。
布局文件:
"1.0" encoding="utf-8"?>
.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_about"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".module.activity.AboutActivity">
.support.design.widget.AppBarLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/actionBarSize"
android:background="?attr/colorPrimary"
android:id="@+id/toolbar"
android:theme="@style/Theme.Toolbar"
app:popupTheme="@style/ToolbarPopupTheme"
app:layout_scrollFlags="scroll|enterAlways">
.support.v7.widget.Toolbar>
.support.design.widget.AppBarLayout>
.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/recycler_view"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
.support.v7.widget.RecyclerView>
.support.design.widget.CoordinatorLayout>
我们先来看AppBarLayout,我们在里面指定了一个ToolBar,在ToolBar中我们设置了Theme,但是有一项是这样的:app:layout_scrollFlags="scroll|enterAlways"
这里layout_scrollFlags就是我们为AppBarLayout子View设置的动作,scroll:值设为scroll的View会跟随滚动事件一起发生移动。enterAlways:值设为enterAlways的View,当ScrollView往下移动时,该View会直接往下滚动。而不用考虑ScrollView是否在滚动。
一般说来,layout_scrollFlags可以为以下几种:
1 scroll:值设为scroll的View会跟随滚动事件一起发生移动。
什么意思呢?简单的说,就是当指定的ScrollView发生滚动时,该View也跟随一起滚动,就好像这个View也是属于这个ScrollView一样。
例如:
布局文件:
.support.design.widget.AppBarLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/actionBarSize"
android:background="?attr/colorPrimary"
android:id="@+id/toolbar"
android:theme="@style/Theme.Toolbar"
app:popupTheme="@style/ToolbarPopupTheme"
app:layout_scrollFlags="scroll">
.support.v7.widget.Toolbar>
.support.design.widget.AppBarLayout>
2 enterAlways:值设为enterAlways的View,当ScrollView往下滚动时,该View会直接往下滚动。而不用考虑ScrollView是否在滚动。
布局文件
.support.design.widget.AppBarLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/actionBarSize"
android:background="?attr/colorPrimary"
android:id="@+id/toolbar"
android:theme="@style/Theme.Toolbar"
app:popupTheme="@style/ToolbarPopupTheme"
app:layout_scrollFlags="scroll|enterAlways">
.support.v7.widget.Toolbar>
.support.design.widget.AppBarLayout>
这个就是我们最开始的效果,它与 1 的不同就是:只要ScrollView在网下滚动,那么没有滚动到头,APPBarLayout中的子View也会跟着一起滚动,1 是只有往下滚动到头了APPBarLayout中的子View才会跟着一起滚动。
3 exitUntilCollapsed:值设为exitUntilCollapsed的View,当这个View要往上逐渐“消逝”时,会一直往上滑动,直到剩下的的高度达到它的最小高度后,再响应ScrollView的内部滑动事件。
怎么理解呢?简单解释:在ScrollView往上滑动时,首先是APPBarLayout中的子View把滑动事件“夺走”,由View去执行滑动,直到滑动最小高度后,把这个滑动事件“还”回去,让ScrollView内部去上滑。
我们给ToolBar设定一个最小高度,先看布局文件:
.support.design.widget.AppBarLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="200dp"
android:minHeight="?android:attr/actionBarSize"
android:background="?attr/colorPrimary"
android:id="@+id/toolbar"
android:theme="@style/Theme.Toolbar"
app:popupTheme="@style/ToolbarPopupTheme"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
.support.v7.widget.Toolbar>
.support.design.widget.AppBarLayout>
效果如下:
4 enterAlwaysCollapsed:是enterAlways的附加选项,一般跟enterAlways一起使用,它是指,View在往下“出现”的时候,首先是enterAlways效果,当View的高度达到最小高度时,View就暂时不去往下滚动,直到ScrollView滑动到顶部不再滑动时,View再继续往下滑动,直到滑到View的顶部结束。
还是先来看布局吧:
.support.design.widget.AppBarLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="200dp"
android:minHeight="?android:attr/actionBarSize"
android:background="?attr/colorPrimary"
android:id="@+id/toolbar"
android:theme="@style/Theme.Toolbar"
app:popupTheme="@style/ToolbarPopupTheme"
app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed">
.support.v7.widget.Toolbar>
.support.design.widget.AppBarLayout>
注意观察,当我最开始向下滑动时,没有ToolBar开始展开到最小宽度,然后我再向下滚动到RecyclerView
的顶部时,ToolBar就又接着展开到200dp了。
我们一直在说“当ScrollView发生滚动时”,那么怎么将AppBarLayout与ScrollView关联起来呢?这里需要用到另一个控件了:CoordinatorLayout,关于CoordinatorLayout,我们这里只是简单的介绍下,后面会单独写一篇来介绍。
简单来说CoordinatorLayout是组织它众多子view之间互相协作的一个ViewGroup。在这里就是组织我们的RecyclerView与APPBarLayout 协调的。我们看我们最开始的布局:
"1.0" encoding="utf-8"?>
.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_about"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".module.activity.AboutActivity">
.support.design.widget.AppBarLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="200dp"
android:minHeight="?android:attr/actionBarSize"
android:background="?attr/colorPrimary"
android:id="@+id/toolbar"
android:theme="@style/Theme.Toolbar"
app:popupTheme="@style/ToolbarPopupTheme"
app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed">
.support.v7.widget.Toolbar>
.support.design.widget.AppBarLayout>
.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/recycler_view"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
.support.v7.widget.RecyclerView>
.support.design.widget.CoordinatorLayout>
发现没?对于RecyclerView我们多了这样一行:
app:layout_behavior="@string/appbar_scrolling_view_behavior">
它就是指定behavior的,appbar_scrolling_view_behavior对应的类的名称是:android.support.design.widget.AppBarLayout$ScrollingViewBehavior感兴趣的可以去分析源码。
这样指定了之后,我们的RecyclerView就和APPBarLayout联系起来了。至于什么事behavior, Behavior就是执行你定制的动作,注意behavior只有是CoordinatorLayout的直接子View才有意义。我们会在后面详细分析CoordinatorLayout与其Behavior的,这里只需要知道怎么用就行了。