應用欄布局AppBarLayout
Android5.0推出工具欄Toolbar用來替代ActionBar,靈活性和易用性大大增強,有關Toolbar的詳細介紹參見《 Android開發筆記(一百一十九)工具欄Toolbar》。
可是僅僅使用Toolbar的話,還是有些呆闆,比如說Toolbar固定占據着頁面頂端,既不能跟着主體頁面移上去,也不會跟着主體頁面拉下來。為了讓App頁面更加生動活潑,勢必要求Toolbar在某些特定的場景上移或者下拉,如此才能滿足酷炫的頁面特效需要。那麼Android5.0也同時給出了相應的解決方案,即推出MaterialDesign庫,通過該庫中的AppBarLayout控件,對Toolbar加以包裝,進而實作頂部工具欄的動态變化效果。
AppBarLayout其實繼承自LinearLayout,是以具備LinearLayout的所有屬性與方法。對于大家關心的額外功能,則主要有以下幾點:
1、支援響應主體頁面的滑動行為,即在主體頁面上移或者下拉時,AppBarLayout能夠捕捉到主體頁面的滾動操作;
2、AppBarLayout捕捉到滾動操作之後,還要通知頭部控件(通常是Toolbar),告訴頭部控件你要怎麼滾,是愛咋咋滾,還是滿大街滾;
具體到實作上,要在工程中做以下修改:
1、添加幾個庫的支援,包括appcompat-v7庫(Toolbar需要)、design庫(AppBarLayout需要)、recyclerview庫(首頁面的RecyclerView需要);
2、布局檔案的根布局采用android.support.design.widget.CoordinatorLayout,因為design庫的動态效果都依賴于該控件;
3、CoordinatorLayout節點要添加命名空間聲明xmlns:app="http://schemas.android.com/apk/res-auto";
4、使用android.support.design.widget.AppBarLayout節點包裹Toobar;
5、Toobar節點添加滾動屬性app:layout_scrollFlags="scroll|enterAlways",聲明工具欄的滾動行為标志;
6、示範頁面的主體頁面使用RecyclerView控件,并給該控件節點添加行為屬性app:layout_behavior="@string/appbar_scrolling_view_behavior",表示通知AppBarLayout捕捉RecyclerView的滾動操作。
下面是AppBarLayout結合RecyclerView實作的工具欄向上滾動效果截圖:

下面是AppBarLayout結合RecyclerView的布局檔案代碼例子:
<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/cl_main"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<android.support.design.widget.AppBarLayout
android:id="@+id/abl_title"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<android.support.v7.widget.Toolbar
android:id="@+id/tl_title"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/blue_light"
app:layout_scrollFlags="scroll|enterAlways" />
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>
嵌套滾動視圖NestedScrollView
雖說通過AppBarLayout可實作Toolbar的滾動效果,但并非所有可滾動的控件都會觸發Toolbar滾動,事實上隻有Android5.0之後新增的少數滾動控件才具備該特技。RecyclerView是其中一個特工,它可用來替代ListView和GridView;替代ScrollView的則另有其人,它便是嵌套滾動視圖NestedScrollView,在Android5.0之後的v4庫中提供。
NestedScrollView繼承自FrameLayout,其用法與ScrollView相似,如都必須且隻能帶一個直接子視圖,都是允許視圖上下滾動等等。NestedScrollView多出來的功能,也就是跟AppBarLayout配合使用,以便觸發Toolbar的滾動行為,你可以把它當作是相容了Android5.0新特性的增強版ScrollView。
下面是AppBarLayout結合NestedScrollView實作的工具欄向上滾動效果截圖:
下面是AppBarLayout結合NestedScrollView的布局檔案代碼例子:
<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/cl_main"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<android.support.design.widget.AppBarLayout
android:id="@+id/abl_title"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<android.support.v7.widget.Toolbar
android:id="@+id/tl_title"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="scroll|enterAlways"
android:background="@color/blue_light" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:id="@+id/nsv_main"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#ffaaaa"
android:gravity="center"
android:text="hello"
android:textColor="#000000"
android:textSize="17sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="800dp"
android:background="#aaffaa"
android:gravity="center"
android:text="world"
android:textColor="#000000"
android:textSize="17sp" />
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
話說除了RecyclerView和NestedScrollView,還有哪些控件可以觸發AppBarLayout的滾動行為呢?這還得從CoordinatorLayout說起,檢視CoordinatorLayout的源代碼,發現它實作了接口NestedScrollingParent,奧秘就在其中,該接口定義了嵌套滾動的父輩行為,與之對應的是定義了嵌套滾動的子輩行為接口NestedScrollingChild。凡是實作了接口NestedScrollingChild的控件,理論上都能夠觸發AppBarLayout去滾動。是以,搜遍Android的SDK源碼,總共也隻有三個控件符合這個條件,它們是RecyclerView、NestedScrollView,以及SwipeRefreshLayout,在布局檔案中使用的名稱如下所示:
RecyclerView : 使用名稱android.support.v7.widget.RecyclerView
NestedScrollView : 使用名稱android.support.v4.widget.NestedScrollView
SwipeRefreshLayout : 使用名稱android.support.v4.widget.SwipeRefreshLayout
AppBarLayout的滾動标志
前面說到給Toobar節點添加滾動屬性app:layout_scrollFlags="scroll|enterAlways",該屬性其實來自于AppBarLayout,用來定義子控件具體的滾動行為,比如說是先滾還是後滾,是滾一半還是全部滾,是自動滾還是手動滾等等。
首先得弄清楚為什麼AppBarLayout劃分了這幾種滾動行為,所謂知其然,還要知其是以然,才更有利于記憶和了解。
1、AppBarLayout的滾動依賴于主體視圖的滾動,與主體視圖相對應的,可将AppBarLayout稱作頭部視圖。既然一個頁面分為頭部和主體兩部分,那麼就存在誰先滾誰後滾的問題了。
2、AppBarLayout内部的高度也可能變化,比如它嵌套了可折疊工具欄布局CollapsingToolbarLayout,有關可折疊工具欄布局的詳細介紹參見《 Android開發筆記(一百三十六)可折疊工具欄布局CollapsingToolbarLayout》。既然AppBarLayout的高度是變化的,那也得區分是滾一半還是滾全部。
3、大家都知道ViewPager是左右滾動的翻頁視圖,使用者通過手勢把頁面橫向拉動一段距離後松開,系統會判斷接下來是自動左滾還是自動右滾,總之最後使用者看到的是一個完整的頁面,而不是拉到一半的頁面。同理,拉動AppBarLayout也有類似情況,當松開手指後,AppBarLayout得判斷要不要繼續向上收縮,或是繼續向下展開。
區分好了各種滾動行為的起因與目的,然後再來談談layout_scrollFlags的标志位取值說明,具體的取值有五個說明如下:
1、scroll : 頭部與主體一起滾動。scroll标志是基礎标志,其他标志都要配合該标志使用;因為隻有通過scroll聲明Toolbar是可以滾動的,才有後面的各種各樣滾動。
如果僅僅聲明scroll,沒有聲明其它标志,則滾動效果如下圖所示:
2、enterAlways : 頭部與主體先一起滾動,頭部滾到位後,主體繼續向上或者向下滾。
同時聲明scroll和enterAlways,滾動效果如下圖所示:
後面三個标志都與CollapsingToolbarLayout有關,得配合該控件才能觀察細節差異。是以本文隻做下面三個标志的概念解釋,有關的效果圖參見《 Android開發筆記(一百三十六)可折疊工具欄布局CollapsingToolbarLayout》。
3、exitUntilCollapsed : 該标志保證頁面上至少能看到最小化的工具欄,不會完全看不到工具欄。具體的滾動說明如下所示:
向上滾動:頭部先往上收縮,一直滾到折疊的最小高度。然後頭部固定不動,主體繼續向上滾動。
向下滾動:頭部固定不動,主體先向下滾動,一直滾到主體全部拉出。然後頭部向下展開。
4、enterAlwaysCollapsed:該标志一般跟enterAlways一起使用,它與enterAlways差別在于有折疊操作,而單獨的enterAlways沒有折疊。具體的滾動說明如下所示:
向上滾動:頭部先往上收縮,一直滾到折疊的最小高度。然後頭部與主體先一起滾動,頭部滾到位後,主體繼續向上。
向下滾動:頭部與主體先一起滾動,一直滾到頭部折疊的最小高度。然後主體向下滾動,滾到位後頭部繼續向下展開。
5、snap : 在使用者手指松開時,系統自行判斷,接下來是全部向上滾到頂,還是全部向下展開。
點選下載下傳本文用到的應用欄布局的工程代碼
點此檢視Android開發筆記的完整目錄