CoordinatorLayout與滾動的處理
泡在網(wǎng)上的日子 發(fā)表于 2015-07-17 17:10 第 30892 次閱讀 CoordinatorLayout
5
編輯推薦:稀土掘金乎婿,這是一個針對技術(shù)開發(fā)者的一個應(yīng)用测僵,你可以在掘金上獲取最新最優(yōu)質(zhì)的技術(shù)干貨,不僅僅是Android知識谢翎、前端捍靠、后端以至于產(chǎn)品和設(shè)計都有涉獵沐旨,想成為全棧工程師的朋友不要錯過!
英文原文:https://guides.codepath.com/android/Handling-Scrolls-with-CoordinatorLayout
這篇文章專門講解和CoordinatorLayout相關(guān)的知識點剂公,這也是Design Support Library中最重要與最難的部分希俩。
概覽
CoordinatorLayout 實現(xiàn)了多種Material Design中提到的滾動效果。目前這個框架提供了幾種不用寫動畫代碼就能工作的方法纲辽,這些效果包括:
讓浮動操作按鈕上下滑動,為Snackbar留出空間璃搜。
擴展或者縮小Toolbar或者頭部拖吼,讓主內(nèi)容區(qū)域有更多的空間。
控制哪個view應(yīng)該擴展還是收縮这吻,以及其顯示大小比例吊档,包括視差滾動效果動畫。
設(shè)置
首先確保遵循了Design Support Library的使用說明唾糯。
浮動操作按鈕與Snackbar
CoordinatorLayout可以用來配合浮動操作按鈕的 layout_anchor 和 layout_gravity屬性創(chuàng)造出浮動效果怠硼,詳情請參見浮動操作按鈕指南。
當Snackbar在顯示的時候移怯,往往出現(xiàn)在屏幕的底部香璃。為了給Snackbar留出空間,浮動操作按鈕需要向上移動舟误。
只要使用CoordinatorLayout作為基本布局葡秒,將自動產(chǎn)生向上移動的動畫。浮動操作按鈕有一個 默認的 behavior來檢測Snackbar的添加并讓按鈕在Snackbar之上呈現(xiàn)上移與Snackbar等高的動畫嵌溢。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<android.support.design.widget.CoordinatorLayout
android:id="@+id/main_content"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/rvToDoList"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
<android.support.design.widget.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:layout_margin="16dp"
android:src="@mipmap/ic_launcher"
app:layout_anchor="@id/rvToDoList"
app:layout_anchorGravity="bottom|right|end"/>
</android.support.design.widget.CoordinatorLayout>
Toolbar的擴展與收縮
首先需要確保你不是使用已經(jīng)過時的ActionBar眯牧。務(wù)必遵循 使用ToolBar作為actionbar這篇文章的指南。同樣赖草,這里也需要CoordinatorLayout作為主布局容器学少。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<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/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
</android.support.design.widget.CoordinatorLayout>
響應(yīng)滾動事件
接下來,我們必須使用一個容器布局:AppBarLayout來讓Toolbar響應(yīng)滾動事件秧骑。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="@dimen/detail_backdrop_height"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
android:fitsSystemWindows="true">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
</android.support.design.widget.AppBarLayout>
注意:根據(jù)官方的谷歌文檔版确,AppBarLayout目前必須是第一個嵌套在CoordinatorLayout里面的子view(現(xiàn)在貌似不是這樣子,正確的理解是:AppBarLayout必須是CoordinatorLayout的直接子View)腿堤。
然后阀坏,我們需要定義AppBarLayout與滾動視圖之間的聯(lián)系。在RecyclerView或者任意支持嵌套滾動的view比如NestedScrollView上添加app:layout_behavior笆檀。support library包含了一個特殊的字符串資源@string/appbar_scrolling_view_behavior忌堂,它和AppBarLayout.ScrollingViewBehavior相匹配,用來通知AppBarLayout 這個特殊的view何時發(fā)生了滾動事件酗洒,這個behavior需要設(shè)置在觸發(fā)事件(滾動)的view之上士修。
1
2
3
4
5
<android.support.v7.widget.RecyclerView
android:id="@+id/rvToDoList"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
當CoordinatorLayout發(fā)現(xiàn)RecyclerView中定義了這個屬性枷遂,它會搜索自己所包含的其他view,看看是否有view與這個behavior相關(guān)聯(lián)棋嘲。AppBarLayout.ScrollingViewBehavior描述了RecyclerView與AppBarLayout之間的依賴關(guān)系酒唉。RecyclerView的任意滾動事件都將觸發(fā)AppBarLayout或者AppBarLayout里面view的改變。
AppBarLayout里面定義的view只要設(shè)置了app:layout_scrollFlags屬性沸移,就可以在RecyclerView滾動事件發(fā)生的時候被觸發(fā):
1
2
3
4
5
6
7
8
9
10
11
12
13
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="scroll|enterAlways"/>
</android.support.design.widget.AppBarLayout>
app:layout_scrollFlags屬性里面必須至少啟用scroll這個flag痪伦,這樣這個view才會滾動出屏幕,否則它將一直固定在頂部雹锣⊥矗可以使用的其他flag有:
enterAlways: 一旦向上滾動這個view就可見。
enterAlwaysCollapsed: 顧名思義蕊爵,這個flag定義的是何時進入(已經(jīng)消失之后何時再次顯示)辉哥。假設(shè)你定義了一個最小高度(minHeight)同時enterAlways也定義了,那么view將在到達這個最小高度的時候開始顯示攒射,并且從這個時候開始慢慢展開醋旦,當滾動到頂部的時候展開完。
exitUntilCollapsed: 同樣顧名思義会放,這個flag時定義何時退出饲齐,當你定義了一個minHeight,這個view將在滾動到達這個最小高度的時候消失鸦概。
記住箩张,要把帶有scroll flag的view放在前面,這樣收回的view才能讓正常退出窗市,而固定的view繼續(xù)留在頂部先慷。
此時,你應(yīng)該注意到我們的Toolbar能夠響應(yīng)滾動事件了咨察。
制造折疊效果
如果想制造toolbar的折疊效果论熙,我們必須把Toolbar放在CollapsingToolbarLayout中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleMarginEnd="64dp"
app:expandedTitleMarginStart="48dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="scroll|enterAlways"></android.support.v7.widget.Toolbar>
</android.support.design.widget.CollapsingToolbarLayout>
現(xiàn)在效果就成了:
通常,我們我們都是設(shè)置Toolbar的title摄狱,而現(xiàn)在脓诡,我們需要把title設(shè)置在CollapsingToolBarLayout上,而不是Toolbar媒役。
1
2
3
CollapsingToolbarLayout collapsingToolbar =
(CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
collapsingToolbar.setTitle("Title");
制造視差效果
CollapsingToolbarLayout還能讓我們做出更高級的動畫祝谚,比如在里面放一個ImageView,然后在它折疊的時候漸漸淡出酣衷。同時在用戶滾動的時候title的高度也會隨著改變交惯。
為了制造出這種效果,我們添加一個定義了app:layout_collapseMode="parallax" 屬性的ImageView。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleMarginEnd="64dp"
app:expandedTitleMarginStart="48dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="scroll|enterAlways"></android.support.v7.widget.Toolbar>
<ImageView
android:src="@drawable/cheese_1"
app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
app:layout_collapseMode="parallax"
android:minHeight="100dp"/>
</android.support.design.widget.CollapsingToolbarLayout>
自定義Behavior
在CoordinatorLayout 與浮動操作按鈕中我們討論了一個自定義behavior的例子席爽。注: 譯文http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0718/3197.html 意荤。
CoordinatorLayout的工作原理是搜索定義了CoordinatorLayout Behavior 的子view,不管是通過在xml中使用app:layout_behavior標簽還是通過在代碼中對view類使用@DefaultBehavior修飾符來添加注解只锻。當滾動發(fā)生的時候玖像,CoordinatorLayout會嘗試觸發(fā)那些聲明了依賴的子view。
要自己定義CoordinatorLayout Behavior齐饮,你需要實現(xiàn)layoutDependsOn() 和onDependentViewChanged()兩個方法捐寥。比如AppBarLayout.Behavior 就定義了這兩個關(guān)鍵方法。這個behavior用于當滾動發(fā)生的時候讓AppBarLayout發(fā)生改變祖驱。
1
2
3
4
5
6
7
8
9
10
11
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
return dependency instanceof AppBarLayout;
}
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
// check the behavior triggered
android.support.design.widget.CoordinatorLayout.Behavior behavior = ((android.support.design.widget.CoordinatorLayout.LayoutParams) dependency.getLayoutParams()).getBehavior();
if (behavior instanceof AppBarLayout.Behavior) {
// do stuff here
}
}
理解如何實現(xiàn)這些自定義behavior的最好途徑是研究AppBarLayout.Behavior 和 FloatingActionButtion.Behavior上真。雖然這些源代碼還沒有放出來,但是你可以使用Android Studio 1.2集成的反編譯器來查看羹膳。