玩转AppBarLayout

qidiai 7年前
   <p>本篇文章会从官方文档出发,从基本使用姿势到工作原理,试图把AppBarLayout彻底讲明白。</p>    <h2><strong>从是什么开始</strong></h2>    <p>首先,我们来看看官方文档中对AppBarLayout的描述:</p>    <p>AppBarLayout是一个垂直的LinearLayout,实现了Material Design中app bar的scrolling gestures特性。AppBarLayout的子View应该声明想要具有的“滚动行为”,这可以通过layout_scrollFlags属性或是setScrollFlags()方法来指定。</p>    <p>AppBarLayout只有作为CoordinatorLayout的直接子View时才能正常工作,</p>    <p>为了让AppBarLayout能够知道何时滚动其子View,我们还应该在CoordinatorLayout布局中提供一个可滚动View,我们称之为scrolling view。scrolling view和AppBarLayout之间的关联,通过将scrolling view的Behavior设为AppBarLayout.ScrollingViewBehavior来建立。</p>    <p>根据上面的描述我们可以知道,AppBarLayout主要用来实现这样的功能:当位于同一父容器中的可滚动View发生滚动时,AppBarLayout会根据子View声明的滚动行为来对其子View进行相应的滚动。这也就是上面描述中提到的scrolling gestures。这么说可能还不够形象,那么我们下面通过实际例子来体会一下。</p>    <h3><strong>app bar</strong></h3>    <p>在介绍scrolling gestures之前,我们先来简单提下app bar的概念。app bar的示意图如下:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/b3d4efb6faf501c7fb434aeb5806d816.png"></p>    <p style="text-align:center">app bar示意图</p>    <p>app bar是Material Design中的一个概念,我们可以把它看做是一种ToolBar。我们把TooBar套上一层AppBarLayout,就能把顶部栏玩出各种花样,比如前面我们提到的scrolling gestures。下面我们来通过一个简单地例子,看看究竟什么是scrolling gestures。</p>    <h3><strong>scrolling gestures</strong></h3>    <p>先看个动图感受下:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/8c35e473f78af203c6ee0a4112cdfbe2.gif"></p>    <p style="text-align:center">scrolling_gesture_demo</p>    <p>当我们向上滚动可滚动View时,ToolBar会消失;当我们再向下滚动可滚动View时,ToolBar又会随之出现。这就是一个简单地scrolling gesture的示例。实际上,ToolBar本身可没有这个能耐,我们通过为它包上一层AppBarLayout,并为ToolBar指定一个滚动行为,就能够让ToolBar随着下面的可滚动View的滚动而发生滚动。可滚动View也就是我们上面提到的scrolling view。</p>    <p>现在,我们对AppBarLayout已经建立起了感性认识,接下来我们来详细介绍下AppBarLayout的用法。</p>    <h2><strong>玩转AppBarLayout</strong></h2>    <p>我们就以上面的简单demo为例子,介绍下AppBarLayout的用法。</p>    <h3><strong>XML布局文件</strong></h3>    <p>上面例子的XML布局文件如下:</p>    <pre>  <code class="language-java"><?xml version="1.0" encoding="utf-8"?>  <android.support.design.widget.CoordinatorLayout      xmlns:android="http://schemas.android.com/apk/res/android"      xmlns:app="http://schemas.android.com/apk/res-auto"      android:id="@+id/coordinator"      android:layout_width="match_parent"      android:layout_height="match_parent"      android:fitsSystemWindows="true">        <android.support.design.widget.AppBarLayout          android:id="@+id/appbar"          android:layout_width="match_parent"          android:layout_height="wrap_content">          <android.support.v7.widget.Toolbar              android:id="@+id/toolbar"              android:layout_width="match_parent"              android:layout_height="?android:attr/actionBarSize"              android:background="?attr/colorPrimary"              app:layout_scrollFlags="scroll" />      </android.support.design.widget.AppBarLayout>        <android.support.v4.widget.NestedScrollView          android:layout_width="match_parent"          android:layout_height="match_parent"          app:layout_behavior="@string/appbar_scrolling_view_behavior">          <WebView              android:id="@+id/web_view"              android:layout_width="match_parent"              android:layout_height="match_parent">          </WebView>      </android.support.v4.widget.NestedScrollView>    </android.support.design.widget.CoordinatorLayout></code></pre>    <p>在上面的布局文件中,NestedScrollView充当了scrolling view的角色,实际上scrolling view需要支持嵌套滚动,通常我们使用NestedScrollView、RecyclerView等已经实现了嵌套滚动的UI控件。关于嵌套滚动,后面的文章中我们会做出详细介绍。</p>    <p>我们注意到,上面Toolbar的layout_scrollFlags属性被设置为了“scroll”,意思是Toolbar会随则scrolling view的滚动而发生滚动,就像我们上面看到的那样。通过为AppBarLayout的子View设定不同的layout_scrollFlags值,可以定义不同的滚动行为,下面我们看一下,layout_scrollFlags的取值有哪几种。</p>    <h3><strong>layout_scrollFlags</strong></h3>    <p>根据官方文档,layout_scrollFlags的取值可以为以下几种。</p>    <p><strong>scroll</strong></p>    <p>设成这个值的效果就好比本View和scrolling view是“一体”的。具体示例我们在上面已经给出。有一点特别需要我们的注意,为了其他的滚动行为生效,必须同时指定scroll和相应的标记,比如我们想要exitUntilCollapsed所表现的滚动行为,必须将layout_scrollFlags指定为“scroll|exitUntilCollapsed”。</p>    <p><strong>exitUntilCollapsed</strong></p>    <p>当本View离开屏幕时,会被“折叠”直到达到其最小高度。我们可以这样理解这个效果:当我们开始向上滚动scrolling view时,本View会先接管滚动事件,这样本View会先进行滚动,直到滚动到了最小高度(折叠了),scrolling view才开始实际滚动。而当本View已完全折叠后,再向下滚动scrolling view,直到scrolling view顶部的内容完全显示后,本View才会开始向下滚动以显现出来。Demo如下:(为了演示效果,把ToolBar高度设为了150dp)</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/0700f19596b0007e9a02370a789722f0.gif"></p>    <p style="text-align:center">exitUntilCollapsed</p>    <p><strong>enterAlways</strong></p>    <p>当scrolling view向下滚动时,本View会一起跟着向下滚动。实际上就好比我们同时对scrolling view和本View进行向下滚动,具体效果如下图所示:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/64584f38bfc55ded2a6fad95fdce91c8.gif"></p>    <p style="text-align:center">enterAlways</p>    <p>仔细观察上图可以发现,与exitUntilCollapsed不同,当scrolling view一开始滚动,ToolBar便已开始跟着滚动,而无需scrolling view将其内容滚动到顶部。</p>    <p><strong>enterAlwaysCollapsed</strong></p>    <p>从名字上就可以看出,这是在enterAlways的基础上,加上了“折叠”的效果。当我们开始向下滚动scrolling view时,本View会一起跟着滚动直到达到其“折叠高度”(即最小高度)。然后当scrolling view滚动至顶部内容完全显示后,再向下滚动scrolling view,本View会继续滚动到完全显示出来。具体效果如下:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/edfd1021d9b373ffd4ea4132c6f7cb4c.gif"></p>    <p style="text-align:center">enterAlwaysCollapsed</p>    <p>注意,要达到上图所示效果,需要把layout_scrollFlags指定为“scroll|enterAlways|enterAlwaysCollapsed”。</p>    <p><strong>snap</strong></p>    <p>在一次滚动结束时,本View很可能只处于“部分显示”的状态,加上这个标记能够达到“要么完全隐藏,要么完全显示”的效果。</p>    <p>到了这里,我们就把AppBarLayout能够实现的滚动行为介绍完毕了,很简单有木有。接下来我们再来介绍一下AppBarLayout的一个亲密朋友——CollapsingToolbarLayout。</p>    <h2><strong>CollapsingToolbarLayout</strong></h2>    <p>按照惯例,先贴一下官方文档对其做的介绍:</p>    <p>CollapsingToolbarLayout通常用来在布局中包裹一个Toolbar,以实现具有“折叠效果“”的顶部栏。它需要是AppBarLayout的直接子View,这样才能发挥出效果。CollapsingToolbarLayout包含以下特性:</p>    <ol>     <li>Collasping title(可折叠标题):当布局完全可见时,这个标题比较大;当折叠起来时,标题也会变小。标题的外观可以通过expandedTextAppearance和collapsedTextAppearance属性来调整。</li>     <li>Content scrim(内容纱布):根据CollapsingToolbarLayout是否滚动到一个临界点,内容纱布会显示或隐藏。可以通过setContentScrim(Drawable)来设置内容纱布。</li>     <li>Status bar scrim(状态栏纱布):也是根据是否滚动到临界点,来决定是否显示。可以通过setStatusBarScrim(Drawable)方法来设置。这个特性只有在Android5.0及其以上版本,我们设置fitSystemWindows为ture时才能生效。</li>     <li>Parallax scrolling children(视差滚动子View):子View可以选择以“视差”的方式来进行滚动。(视觉效果上就是子View滚动的比其他View稍微慢些)</li>     <li>Pinned position children:子View可以选择固定在某一位置上。</li>    </ol>    <p>上面的描述有些抽象,实际上对于Content scrim、Status bar scrim我们可以暂时予以忽略,只要留个大概印象待以后需要时再查阅相关资料即可。下面我们通过一个常见的例子介绍下CollapsingToolbarLayout的基本使用姿势。</p>    <h3><strong>如何使用CollapsingToolbarLayout</strong></h3>    <p>先看效果:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/e8b675eab6d4c0f63d11fee165810bf7.gif"></p>    <p style="text-align:center">collapsingToolbar</p>    <p>我们可以看到,顶部栏会随着scrolling view向上滚动而折叠。接下来看一下这个效果究竟是怎样实现的。</p>    <p><strong>XML布局文件</strong></p>    <pre>  <code class="language-java"><?xml version="1.0" encoding="utf-8"?>  <android.support.design.widget.CoordinatorLayout      xmlns:android="http://schemas.android.com/apk/res/android"      xmlns:app="http://schemas.android.com/apk/res-auto"      android:id="@+id/coordinator"      android:layout_width="match_parent"      android:layout_height="match_parent">        <android.support.design.widget.AppBarLayout          android:id="@+id/app_bar"          android:layout_width="match_parent"          android:layout_height="256dp"          android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">          <android.support.design.widget.CollapsingToolbarLayout              android:id="@+id/collapsing_toolbar"              android:layout_width="match_parent"              android:layout_height="match_parent"              app:expandedTitleMarginEnd="50dp"              app:expandedTitleMarginStart="50dp"              app:layout_scrollFlags="scroll|exitUntilCollapsed">              <ImageView                  android:src="@mipmap/ic_launcher"                  android:id="@+id/image"                  android:layout_width="match_parent"                  android:layout_height="match_parent"                  android:scaleType="centerCrop"                  app:layout_collapseMode="parallax" />              <android.support.v7.widget.Toolbar                  android:id="@+id/toolbar"                  android:layout_width="match_parent"                  android:layout_height="?attr/actionBarSize"                  app:layout_collapseMode="pin" />          </android.support.design.widget.CollapsingToolbarLayout>      </android.support.design.widget.AppBarLayout>        <android.support.v4.widget.NestedScrollView          android:layout_width="match_parent"          android:layout_height="match_parent"          app:layout_behavior="@string/appbar_scrolling_view_behavior">          <WebView              android:id="@+id/web_view"              android:layout_width="match_parent"              android:layout_height="match_parent">          </WebView>   </android.support.v4.widget.NestedScrollView>    </android.support.design.widget.CoordinatorLayout></code></pre>    <p>我们在XML文件中为CollapsingToolbarLayout的layout_scrollFlags指定为“scroll|exitUntilCollapsed”,这样便实现了向上滚动scrolling view时的折叠效果。</p>    <p>CollapsingToolbarLayout本质上是一个FrameLayout。我们在布局文件中为它指定了两个子View,分别是ImageView和Toolbar。ImageView的layout_collapseMode属性设为了parallax,也就是我们前面介绍的视差滚动;而Toolbar的layout_collaspeMode设为了pin,也就是Toolbar会始终固定在顶部。</p>    <p><strong>contentScrim</strong></p>    <p>在上图中,我们看到Toolbar的背景一直都是我们指定的图片,即时图片向上滚动到消失后也是这样。那么可不可以让图片完全消失后,Toolbar显示一个另外的背景呢?答案是肯定的,只要使用我们上面提到的“内容纱布”即可。还记得我们上面关于内容纱布的介绍吗?当CollapsingToolbarLayout滚动到一个临界位置,内容纱布就会显现出来,我们通过一个例子感受下。</p>    <p>我们把CollapsingToolbarLayout的contentScrim属性指定为"?attr/colorPrimary"后,再运行一下Demo,可以得到如下效果:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/eede76e8bb7563106451f5e69936d3a4.gif"></p>    <p style="text-align:center">contentScrim</p>    <p>我们可以看到,当CollapsingToolbarLayout完全折叠后,ToolBar的背景变为了黑色,好像盖上了一层布,所以这个属性叫做“内容纱布”。这里我们发现,只有CollapsingToolbarLayout滚动到折叠后,内容纱布才显现出来,也就是说,默认的临界位置就是滚动到折叠。</p>    <p> </p>    <p>来自:http://www.jianshu.com/p/9e87e5912199</p>    <p> </p>