玩轉AppBarLayout
本篇文章會從官方文檔出發,從基本使用姿勢到工作原理,試圖把AppBarLayout徹底講明白。
從是什么開始
首先,我們來看看官方文檔中對AppBarLayout的描述:
AppBarLayout是一個垂直的LinearLayout,實現了Material Design中app bar的scrolling gestures特性。AppBarLayout的子View應該聲明想要具有的“滾動行為”,這可以通過layout_scrollFlags屬性或是setScrollFlags()方法來指定。
AppBarLayout只有作為CoordinatorLayout的直接子View時才能正常工作,
為了讓AppBarLayout能夠知道何時滾動其子View,我們還應該在CoordinatorLayout布局中提供一個可滾動View,我們稱之為scrolling view。scrolling view和AppBarLayout之間的關聯,通過將scrolling view的Behavior設為AppBarLayout.ScrollingViewBehavior來建立。
根據上面的描述我們可以知道,AppBarLayout主要用來實現這樣的功能:當位于同一父容器中的可滾動View發生滾動時,AppBarLayout會根據子View聲明的滾動行為來對其子View進行相應的滾動。這也就是上面描述中提到的scrolling gestures。這么說可能還不夠形象,那么我們下面通過實際例子來體會一下。
app bar
在介紹scrolling gestures之前,我們先來簡單提下app bar的概念。app bar的示意圖如下:
app bar示意圖
app bar是Material Design中的一個概念,我們可以把它看做是一種ToolBar。我們把TooBar套上一層AppBarLayout,就能把頂部欄玩出各種花樣,比如前面我們提到的scrolling gestures。下面我們來通過一個簡單地例子,看看究竟什么是scrolling gestures。
scrolling gestures
先看個動圖感受下:
scrolling_gesture_demo
當我們向上滾動可滾動View時,ToolBar會消失;當我們再向下滾動可滾動View時,ToolBar又會隨之出現。這就是一個簡單地scrolling gesture的示例。實際上,ToolBar本身可沒有這個能耐,我們通過為它包上一層AppBarLayout,并為ToolBar指定一個滾動行為,就能夠讓ToolBar隨著下面的可滾動View的滾動而發生滾動。可滾動View也就是我們上面提到的scrolling view。
現在,我們對AppBarLayout已經建立起了感性認識,接下來我們來詳細介紹下AppBarLayout的用法。
玩轉AppBarLayout
我們就以上面的簡單demo為例子,介紹下AppBarLayout的用法。
XML布局文件
上面例子的XML布局文件如下:
<?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>
在上面的布局文件中,NestedScrollView充當了scrolling view的角色,實際上scrolling view需要支持嵌套滾動,通常我們使用NestedScrollView、RecyclerView等已經實現了嵌套滾動的UI控件。關于嵌套滾動,后面的文章中我們會做出詳細介紹。
我們注意到,上面Toolbar的layout_scrollFlags屬性被設置為了“scroll”,意思是Toolbar會隨則scrolling view的滾動而發生滾動,就像我們上面看到的那樣。通過為AppBarLayout的子View設定不同的layout_scrollFlags值,可以定義不同的滾動行為,下面我們看一下,layout_scrollFlags的取值有哪幾種。
layout_scrollFlags
根據官方文檔,layout_scrollFlags的取值可以為以下幾種。
scroll
設成這個值的效果就好比本View和scrolling view是“一體”的。具體示例我們在上面已經給出。有一點特別需要我們的注意,為了其他的滾動行為生效,必須同時指定scroll和相應的標記,比如我們想要exitUntilCollapsed所表現的滾動行為,必須將layout_scrollFlags指定為“scroll|exitUntilCollapsed”。
exitUntilCollapsed
當本View離開屏幕時,會被“折疊”直到達到其最小高度。我們可以這樣理解這個效果:當我們開始向上滾動scrolling view時,本View會先接管滾動事件,這樣本View會先進行滾動,直到滾動到了最小高度(折疊了),scrolling view才開始實際滾動。而當本View已完全折疊后,再向下滾動scrolling view,直到scrolling view頂部的內容完全顯示后,本View才會開始向下滾動以顯現出來。Demo如下:(為了演示效果,把ToolBar高度設為了150dp)
exitUntilCollapsed
enterAlways
當scrolling view向下滾動時,本View會一起跟著向下滾動。實際上就好比我們同時對scrolling view和本View進行向下滾動,具體效果如下圖所示:
enterAlways
仔細觀察上圖可以發現,與exitUntilCollapsed不同,當scrolling view一開始滾動,ToolBar便已開始跟著滾動,而無需scrolling view將其內容滾動到頂部。
enterAlwaysCollapsed
從名字上就可以看出,這是在enterAlways的基礎上,加上了“折疊”的效果。當我們開始向下滾動scrolling view時,本View會一起跟著滾動直到達到其“折疊高度”(即最小高度)。然后當scrolling view滾動至頂部內容完全顯示后,再向下滾動scrolling view,本View會繼續滾動到完全顯示出來。具體效果如下:
enterAlwaysCollapsed
注意,要達到上圖所示效果,需要把layout_scrollFlags指定為“scroll|enterAlways|enterAlwaysCollapsed”。
snap
在一次滾動結束時,本View很可能只處于“部分顯示”的狀態,加上這個標記能夠達到“要么完全隱藏,要么完全顯示”的效果。
到了這里,我們就把AppBarLayout能夠實現的滾動行為介紹完畢了,很簡單有木有。接下來我們再來介紹一下AppBarLayout的一個親密朋友——CollapsingToolbarLayout。
CollapsingToolbarLayout
按照慣例,先貼一下官方文檔對其做的介紹:
CollapsingToolbarLayout通常用來在布局中包裹一個Toolbar,以實現具有“折疊效果“”的頂部欄。它需要是AppBarLayout的直接子View,這樣才能發揮出效果。CollapsingToolbarLayout包含以下特性:
- Collasping title(可折疊標題):當布局完全可見時,這個標題比較大;當折疊起來時,標題也會變小。標題的外觀可以通過expandedTextAppearance和collapsedTextAppearance屬性來調整。
- Content scrim(內容紗布):根據CollapsingToolbarLayout是否滾動到一個臨界點,內容紗布會顯示或隱藏。可以通過setContentScrim(Drawable)來設置內容紗布。
- Status bar scrim(狀態欄紗布):也是根據是否滾動到臨界點,來決定是否顯示。可以通過setStatusBarScrim(Drawable)方法來設置。這個特性只有在Android5.0及其以上版本,我們設置fitSystemWindows為ture時才能生效。
- Parallax scrolling children(視差滾動子View):子View可以選擇以“視差”的方式來進行滾動。(視覺效果上就是子View滾動的比其他View稍微慢些)
- Pinned position children:子View可以選擇固定在某一位置上。
上面的描述有些抽象,實際上對于Content scrim、Status bar scrim我們可以暫時予以忽略,只要留個大概印象待以后需要時再查閱相關資料即可。下面我們通過一個常見的例子介紹下CollapsingToolbarLayout的基本使用姿勢。
如何使用CollapsingToolbarLayout
先看效果:
collapsingToolbar
我們可以看到,頂部欄會隨著scrolling view向上滾動而折疊。接下來看一下這個效果究竟是怎樣實現的。
XML布局文件
<?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>
我們在XML文件中為CollapsingToolbarLayout的layout_scrollFlags指定為“scroll|exitUntilCollapsed”,這樣便實現了向上滾動scrolling view時的折疊效果。
CollapsingToolbarLayout本質上是一個FrameLayout。我們在布局文件中為它指定了兩個子View,分別是ImageView和Toolbar。ImageView的layout_collapseMode屬性設為了parallax,也就是我們前面介紹的視差滾動;而Toolbar的layout_collaspeMode設為了pin,也就是Toolbar會始終固定在頂部。
contentScrim
在上圖中,我們看到Toolbar的背景一直都是我們指定的圖片,即時圖片向上滾動到消失后也是這樣。那么可不可以讓圖片完全消失后,Toolbar顯示一個另外的背景呢?答案是肯定的,只要使用我們上面提到的“內容紗布”即可。還記得我們上面關于內容紗布的介紹嗎?當CollapsingToolbarLayout滾動到一個臨界位置,內容紗布就會顯現出來,我們通過一個例子感受下。
我們把CollapsingToolbarLayout的contentScrim屬性指定為"?attr/colorPrimary"后,再運行一下Demo,可以得到如下效果:
contentScrim
我們可以看到,當CollapsingToolbarLayout完全折疊后,ToolBar的背景變為了黑色,好像蓋上了一層布,所以這個屬性叫做“內容紗布”。這里我們發現,只有CollapsingToolbarLayout滾動到折疊后,內容紗布才顯現出來,也就是說,默認的臨界位置就是滾動到折疊。
來自:http://www.jianshu.com/p/9e87e5912199