CoordinatorLayout是support.design包中的控件,它可以說是Design庫中最重要的控件。
他提供了一種全新的布局玩法 - 折疊(關(guān)聯(lián)),何為折疊,就是讓一些指定控件的位置,形態(tài)隨著指定的控件的變化而變化,最簡單的例子,就是標題欄隨著列表的滾動而顯示或消失或這折疊,這是5.0添加的新特性,之前我們監(jiān)聽滾動列表的滾動狀態(tài)也可以做到這個效果,但是代碼會很耦合。這次 google 提供了這個 CoordinatorLayout 頂層容器,配合 Behavior 來封裝解耦了這個需求,讓我們編寫相關(guān)業(yè)務(wù)代碼更簡單,同理效果也是更好。
本地 demo 地址: github
有個別人的簡單入門:
核心套路
我先說說 CoordinatorLayout 的核心套路,這里插一句是為了以后好找:
- 給管滾動控件加 app:layout_behavior="@string/appbar_scrolling_view_behavior"
- 給 CollapsingToolbarLayout 設(shè)置
- 滾動樣式:app:layout_scrollFlags="scroll|exitUntilCollapsed"
- 折疊后標題欄顏色:app:contentScrim="@color/colorAccent"
- 折疊后系統(tǒng)狀態(tài)欄欄顏色:app:layout_scrollFlags="scroll|exitUntilCollapsed"
- 給具體的 view 設(shè)置折疊模式: app:layout_collapseMode="pin"
CoordinatorLayout 使用詳細講解
這里有2個概念:
- CoordinatorLayout
頂層容器,用來協(xié)調(diào)配合子 view 的位置,狀態(tài)關(guān)聯(lián)。 - Behavior
定義了子 view 具體的關(guān)聯(lián)行為。
Design 里面有默認的 Behavior 實現(xiàn),就是一下這個 layout 組合:
<android.support.design.widget.CoordinatorLayout
android:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:fitsSystemWindows="true"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.design.widget.CollapsingToolbarLayout
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:statusBarScrim="@color/colorAccent"
app:titleEnabled="false"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<android.support.v7.widget.Toolbar
app:popupTheme="@style/AppTheme.PopupOverlay"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.7"
app:layout_collapseMode="pin"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
app:layout_behavior="@string/appbar_scrolling_view_behavior">
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
就是上面這幾個布局 CoordinatorLayout + AppBarLayout + CollapsingToolbarLayout + Toolbar + NestedScrollView
這里有2個角色劃分:
- 關(guān)聯(lián)發(fā)起者,提供/觸發(fā)滾動事件
這里的關(guān)聯(lián)發(fā)起者就是可以滾動的 view,上面的例子用的是 NestedScrollView ,當然也可以是 RecyclerView,只要可以滾動就行,最重要的是給滾動控件設(shè)置 layout_behavior
app:layout_behavior="@string/appbar_scrolling_view_behavior">
設(shè)置 layout_behavior 標記,就是設(shè)置發(fā)起滾動關(guān)聯(lián)的事件源
- 關(guān)聯(lián)消費者,消費滾動事件的
就是這個 Behavior 了,系統(tǒng)有默認的實現(xiàn)了 Behavior 的控件,就是上面例子我們使用的- AppBarLayout
- CollapsingToolbarLayout
- Toolbar
剩下的 view 就需要我們自已去定義 Behavior 的行為了,具體的在自定義 Behavior 的章節(jié)再說。這里先說系統(tǒng)提供的。
系統(tǒng)默認提供的 Behavior
系統(tǒng) activity 模板里的 ScrollingActivity ,使用的就是系統(tǒng)提供的 Behavior ,是我們學習 Behavior 的最好的初始資料,我們先來看這個

系統(tǒng)的 xml 布局定義:
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="com.bloodcrown.croodnatorlayouttest2.ScrollingActivity">
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="@dimen/app_bar_height"
android:fitsSystemWindows="true"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/toolbar_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
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_collapseMode="pin"
app:popupTheme="@style/AppTheme.PopupOverlay"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="com.bloodcrown.croodnatorlayouttest2.ScrollingActivity"
tools:showIn="@layout/activity_scrolling">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin"
android:text="@string/large_text"/>
</android.support.v4.widget.NestedScrollView>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/fab_margin"
app:layout_anchor="@id/app_bar"
app:layout_anchorGravity="bottom|end"
app:srcCompat="@android:drawable/ic_dialog_email"/>
</android.support.design.widget.CoordinatorLayout>
恩,這個布局精簡過后,就是我們上面列的默認的 Behavior 實現(xiàn)Behavior 實現(xiàn) layout 組合:
<android.support.design.widget.CoordinatorLayout>
<android.support.design.widget.AppBarLayout>
<android.support.design.widget.CollapsingToolbarLayout
app:contentScrim="?attr/colorPrimary"
app:statusBarScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<android.support.v7.widget.Toolbar
app:layout_collapseMode="pin"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</android.support.design.widget.CoordinatorLayout>
好了這里就是重點了,大家注意
先說說這幾個布局的嵌套關(guān)系
- CoordinatorLayout
必須是頂層布局,behavior 就是CoordinatorLayout 提供的特性,沒有CoordinatorLayout 作為頂層布局,behavior 不起作用 - AppBarLayout
標題欄總部局,繼承的是 LinearLayout ,里面放折疊布局 CollapsingToolbarLayout 等,不放在 CollapsingToolbarLayout 的 view 不參與折疊效果 - CollapsingToolbarLayout
折疊布局,放在這里面的 view 都會參與折疊,當然你也可以設(shè)置關(guān)閉折疊模式。
然后呢,再來看看這幾個布局的參數(shù)設(shè)置:
滾動布局設(shè)置參數(shù):
- layout_behavior
給滾動控件設(shè)置 layout_behavior 標記,聲明該滾動控件對外提供滾動關(guān)聯(lián)事件,這里使用系統(tǒng)默認提供的值,
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
AppBarLayout 的參數(shù)設(shè)置:
layout_scrollFlags,這是 AppBarLayout 的滾動模式設(shè)置,有5種值,給標題欄中需要滾動的部分設(shè)置,不設(shè)置的 view 不會參與滾動
- scroll
此布局和滾動事件關(guān)聯(lián) - enterAlways
向下滾動時,此布局展開 - enterAlwaysCollapsed
假設(shè)你定義了一個最小高度(minHeight)同時enterAlways也定義了,那么view將在到達這個最小高度的時候開始顯示,并且從這個時候開始慢慢展開,當滾動到頂部的時候展開完。 - exitUntilCollapsed
當你定義了一個minHeight,此布局將在滾動到達這個最小高度的時候折疊。 - snap
當一個滾動事件結(jié)束,如果視圖是部分可見的,那么它將被滾動到收縮或展開。例如,如果視圖只有底部25%顯示,它將折疊。相反,如果它的底部75%可見,那么它將完全展開。
CollapsingToolbarLayout 的參數(shù)設(shè)置:
contentScrim / statusBarScrim,這2個屬性,是設(shè)置標題欄在折疊后的內(nèi)容顏色和狀態(tài)欄顏色
- contentScrim
內(nèi)容顏色,默認使用 colorPrimary 的色值 - statusBarScrim
狀態(tài)欄顏色,默認使用 colorPrimaryDark 的色值 - layout_collapseMode
CollapsingToolbarLayout 布局中 view 的折疊模式,有3種模式,注意是給CollapsingToolbarLayout 中的子布局使用的,注意他和layout_scrollFlags的區(qū)別,layout_scrollFlags是使用外層的:- off
這個是默認屬性,布局將正常顯示,沒有折疊的行為。 - pin
CollapsingToolbarLayout折疊后,此布局將固定在頂部。 - parallax
CollapsingToolbarLayout折疊時,此布局也會有視差折疊效果
- off
- layout_collapseParallaxMultiplier
視差滾動因子,值為:0~1。
FloatingActionButton 的參數(shù)設(shè)置:
- layout_anchor
設(shè)置錨點,F(xiàn)loatingActionButton 的中心點和誰對齊 - layout_anchorGravity
錨點對齊位置
好了這些布局的關(guān)系和屬性設(shè)置我們都了解了之后就可以自己來玩來,這里面可是大有可為的,咱們來好好玩玩
自由使用系統(tǒng)默認提供的 Behavior
我們不要局限在系統(tǒng)給我們提供的 ScrollActivity 的寫法中,適當?shù)淖兺ㄟ€是可以有點啊,比如現(xiàn)在很常見的,標題欄中我們加一張圖片進去做打底圖,或者不用 toolBar ,自己封裝組合 view 都是可以的,我們先來做下面這個樣式的

這個實現(xiàn)還是很簡單的,我們先來看看 xml 的寫法
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:fitsSystemWindows="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.bloodcrown.croodnatorlayouttest2.FreeActivity1">
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="@dimen/app_bar_height"
android:fitsSystemWindows="true"
app:theme="@style/AppTheme.AppBarOverlay">
<android.support.design.widget.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="@color/colorAccent"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:statusBarScrim="@color/colorAccent"
app:titleEnabled="false">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:scaleType="centerCrop"
android:src="@mipmap/x001"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.7"/>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="@style/AppTheme.PopupOverlay"
app:title="">
<!--<TextView-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--android:layout_gravity="top|left"-->
<!--android:gravity="top|left"-->
<!--android:text="測試"/>-->
</android.support.v7.widget.Toolbar>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="com.bloodcrown.croodnatorlayouttest2.ScrollingActivity"
tools:showIn="@layout/activity_scrolling">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin"
android:text="@string/large_text"/>
</android.support.v4.widget.NestedScrollView>
<android.support.design.widget.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="@dimen/fab_margin"
android:src="@mipmap/ic_launcher_round"
app:layout_anchor="@id/app_bar"
app:layout_anchorGravity="bottom|right"/>
錄屏時toolbar 里面的 textview 注釋了,效果圖里看不到,實際上還是能正常顯示的,大家放心。
我們首先讓系統(tǒng)狀態(tài)爛透明,這樣才能讓圖片實現(xiàn)頂置顯示
public class FreeActivity1 extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_free1);
intiStateView();
}
private void intiStateView() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WindowManager.LayoutParams layoutParams = getWindow().getAttributes();
layoutParams.flags = (layoutParams.flags | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
}
CollapsingToolbarLayout 折疊布局繼承幀布局,我們在里面放什么view 都行,只要設(shè)置扯著模式就行,這里放入了一個 imageview,使用了0.7的折疊視差效果,和起點 app 小說詳情頁
的標題欄一樣,滾動時收縮都是帶視差效果的。
以下有2個注意點:
fitsSystemWindows 屬性
在我們設(shè)置系統(tǒng)狀態(tài)欄透明后,會造成 toolbar 占用系統(tǒng)狀態(tài)欄的位置的問題,這時我們需要 設(shè)置android:fitsSystemWindows="true" 這個屬性。這個 fitsSystemWindows 屬性,要從跟布局一直設(shè)置到具體的填充系統(tǒng)狀態(tài)爛的布局才行(在例子中是imageview 這個 view),有些麻煩。
我的xml 設(shè)置:
<android.support.design.widget.CoordinatorLayout
android:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:fitsSystemWindows="true">
<android.support.design.widget.CollapsingToolbarLayout
android:fitsSystemWindows="true">
<ImageView
android:fitsSystemWindows="true"/>
toolbar 占用系統(tǒng)狀態(tài)欄的位置:這里把 toolbar 的顏色設(shè)置為黑色


不知道大家注意沒有,我們設(shè)置 android:fitsSystemWindows="true" 后,就是給 toolbar 內(nèi)部添加了一個系統(tǒng)狀態(tài)欄高度的 maggin,要是在標題欄在展開模式時 toolbar 沒有自己的顏色設(shè)置的話,其實這個 fitsSystemWindows 寫不寫都行,寫了toolbar 的內(nèi)容會往下走一點,不寫toolbar 的內(nèi)容會正好卡在系統(tǒng)狀態(tài)爛的下面,覺得貼的緊的話,自己加一個 padding 上去也可以的,具體的還是看需求,在這里把問題高清楚方便之后我們的具體使用

這張圖是我們添加 fitsSystemWindows="true" 之后,toolbar 的位置在狀態(tài)欄的下面,toolbar 黑色背景真丑,但是為了看看效果也是沒辦法的。這個 toolbar 里面的 textview 的位置設(shè)置的是 top|left,文字上面的 maggin和系統(tǒng)狀態(tài)欄的高度其實是一樣的。所以說設(shè)置 fitsSystemWindows 標記,就是給 toolbar 加了一個系統(tǒng)狀態(tài)欄高度的 maggin
toolbar 的使用方式
toolbar的使用有2種:
-
和系統(tǒng)的 actionbar 關(guān)聯(lián)
- height 高度必須使用系統(tǒng)默認值 ?attr/actionBarSize,不能是別的值
- 這時 toolbar 不能作為一個 layout 使用,toolbar 就算放置了 view 也不會顯示
-
單純作為一個layout 使用
- 這時 toolbar 可以作為一個 layout 使用,內(nèi)部可以放 view,并且會正常顯示出來
- actionbar 的那個特性就都用不了了,比如menuitem 的那3個小點點就會顯示了
- height 高度可以是任何值,上面那個系統(tǒng)默認值,wrap 和具體值都可以
具體取舍看具體需求把,我比較喜歡單純當做 layout 來用,這樣靈活。
toolbar和系統(tǒng)的 actionbar 關(guān)聯(lián) 代碼
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
搭配 TabLayout 使用
在頁面的編寫時常常會用到 TabLayout ,或是替代的開源庫,這個我們應(yīng)該怎么和我們上面的例子結(jié)合呢,為啥說這個呢,因為 appbarlayout 在折疊后,高度會是 toolbar 的高度,這時候 toolbar 的高度要適配 TabLayout 的高度才行,要不就會擠在一起

那么我們怎么解決這個問題呢,看下面:
在xml中 TabLayout 和 Toolbar 同級,toolbar 的高度設(shè)置為 tollbar 本身的 height + TabLayout 的 height ,這種做法需要知道 TabLayout 和 Toolbar 的確切高度值。xml 里面要是height 沒有確定值那就用代碼計算一下再設(shè)置也行
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="@dimen/app_bar_height"
android:fitsSystemWindows="true"
app:theme="@style/AppTheme.AppBarOverlay">
<android.support.design.widget.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="@color/colorAccent"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:statusBarScrim="@color/colorAccent"
app:title=""
app:titleEnabled="false">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:scaleType="centerCrop"
android:src="@mipmap/x001"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.7"/>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="90dp"
app:layout_collapseMode="pin"
app:popupTheme="@style/AppTheme.PopupOverlay"
app:title="">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|left"
android:gravity="top|left"
android:text="測試"
android:textSize="16sp"/>
</android.support.v7.widget.Toolbar>
<android.support.design.widget.TabLayout
android:id="@+id/view_tab"
android:layout_width="match_parent"
android:layout_height="45dp"
android:layout_gravity="bottom"
android:gravity="center_vertical"></android.support.design.widget.TabLayout>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>

為啥要特別說 tablayout 呢,因為上面我們要讓 tablayout 站在背景圖片中,參與折疊,要是不在背景圖片就不要放到 CollapsingToolbarLayout 里面就好了,更省事。
這段是我 copy 過來的:
TabLayout沒有設(shè)置app:layout_collapseMode,在CollapsingToolbarLayout收縮時就不會消失。
CollapsingToolbarLayout收縮時的高度是Toolbar的高度,所以我們需要把Toolbar的高度增加,給TabLayout留出位置,這樣收縮后TabLayout就不會和Toolbar重疊。
Toolbar的高度增加,title會相應(yīng)下移。android:gravity="top"方法使Toolbar的title位于Toolbar的上方,然后通過app:titleMarginTop調(diào)整下title距頂部高度,這樣Toolbar就和原來顯示的一樣了。
仿 bilibili 視頻詳情頁
圖我是 copy 過來的,放嗶哩嗶哩這個也算是經(jīng)典學習類目之一了

我錄屏轉(zhuǎn)換gif 太大了,特意壓縮了下分辨率才能傳上來,效果可能不是很好

分析下思路:
- toolbar 固定在頂部
- 監(jiān)聽 appbarlayout,在折疊和展開時,toolbar 顯示不同的 view
- 點擊 FloatingActionButton ,讓appbarlayout不再相應(yīng)滾動事件
- 點擊播放可以使 appbarlayout 從折疊狀態(tài)切換到展開狀態(tài)
基本需求和思路就是上面幾條,前面的例子玩會了,我們搭建這個 bilibili 頁面就會了,區(qū)別在于 toolbar 在折疊和展開時,顯示不同的 view。
toolbar 定義不同的狀態(tài)的 view
這個簡單,這里我把 toolbar 作為 layout 使用,不可系統(tǒng) actionbar 管理,里面定義2條 view ,一個顯示,一個隱藏
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="50dp"
app:layout_collapseMode="pin"
app:popupTheme="@style/AppTheme.PopupOverlay"
app:title="">
<android.support.constraint.ConstraintLayout
android:id="@+id/appbar_show"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_arrow_back_black_24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="BiLiBiLi大講堂開播啦"
android:textColor="@android:color/white"
android:textSize="22sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</android.support.constraint.ConstraintLayout>
<android.support.constraint.ConstraintLayout
android:id="@+id/appbar_hint"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:visibility="gone">
<ImageView
android:id="@+id/appbar_hint_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_play_circle_filled_black_24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/appbar_hint_name"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="@+id/appbar_hint_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="立即播放"
android:textColor="@android:color/white"
android:textSize="22sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@+id/appbar_hint_icon"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</android.support.constraint.ConstraintLayout>
</android.support.v7.widget.Toolbar>
可以看到我定義了 show 和 hint 2個 view,對于展開和折疊狀態(tài)
監(jiān)聽 appbarlayout
CollapsingToolbarLayout 收縮布局本身沒有監(jiān)聽函數(shù),他也是監(jiān)聽 appbarlayout 實現(xiàn)動畫的,這里我們也去監(jiān)聽 appbarlayout 的滾動變化,自己記錄維護 appbarlayout 的展開和折疊狀態(tài)值。
先定義 appbarlayout 的3種狀態(tài)值
// appbar展開狀態(tài)
public static final int STAET_EXPANDED = 1;
// appbar折疊狀態(tài)
public static final int STAET_COLLAPSED = -1;
// appbar中間狀態(tài)
public static final int STAET_ING = 0;
然后再去監(jiān)聽 appbarlayout 滾動變化
mAppBar.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
// int totalScrollRange = appBarLayout.getTotalScrollRange();
// Log.d("AAA", "total:" + totalScrollRange + "/Offset:" + verticalOffset);
verticalOffset = Math.abs(verticalOffset);
// 初始展開狀態(tài)
if (verticalOffset == 0) {
if (state != STAET_EXPANDED) {
// 是展開狀態(tài),重置標記為展開,顯示 appbar 布局控件
state = STAET_EXPANDED;
appBar_show.setVisibility(View.VISIBLE);
appBar_hint.setVisibility(View.GONE);
}
return;
}
// 折疊狀態(tài)
if (verticalOffset >= appBarLayout.getTotalScrollRange()) {
if (state != STAET_COLLAPSED) {
// 是折疊狀態(tài),重置標記為折疊,顯示 appbar 布局控件
state = STAET_COLLAPSED;
appBar_hint.setVisibility(View.VISIBLE);
appBar_show.setVisibility(View.GONE);
}
return;
}
// 中間狀態(tài)
if (state != STAET_ING) {
// 是中間狀態(tài),重置標記為ing,顯示 appbar 布局控件
state = STAET_ING;
appBar_show.setVisibility(View.VISIBLE);
appBar_hint.setVisibility(View.GONE);
}
}
});
這里面有幾個注意點:
- verticalOffset
這個函數(shù)返回的參數(shù)是表示當前 appbarlayout 的累計滾動偏移量,是負數(shù),我們要取絕對值才行,這里我也是打印數(shù)值之后才知道的, 為啥是負數(shù)呢,因為 appbarlayout 的 Y 軸在向上運動,就是在減少啊,所以是負數(shù)啊。 - appbarlayout 可以滾動的最大值
appBarLayout.getTotalScrollRange() 這個方法可以返回最大值,然后我們判斷累計滾動偏移量大于等于這個最大值了,就是處于折疊到底的狀態(tài)了。
appbarlayout不再相應(yīng)滾動事件
這個好做,現(xiàn)成的 api,只要讓滾動 view 不再發(fā)射滾動事件就行了
mFAB.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (state == STAET_EXPANDED) {
if (state_scroll == SCROLL_ING) {
// 取消滾動控件的嵌套滾動,核心的就是這個函數(shù)了,大家注意啊
mScrollView.setNestedScrollingEnabled(false);
state_scroll = SCROLL_NO;
} else if (state_scroll == SCROLL_NO) {
mScrollView.setNestedScrollingEnabled(true);
state_scroll = SCROLL_ING;
}
}
}
});
折疊狀態(tài)切換到展開狀態(tài)
這個頁簡單,現(xiàn)成的 api, setExpanded(true)
mPlayButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (state == STAET_COLLAPSED) {
// 處于折疊狀態(tài)時才能玩
mAppBar.setExpanded(true);
state = STAET_EXPANDED;
}
}
});
完整代碼:
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="com.bloodcrown.croodnatorlayouttest2.FreeActivity1">
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="@dimen/app_bar_height"
android:fitsSystemWindows="true"
app:theme="@style/AppTheme.AppBarOverlay">
<android.support.design.widget.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="@color/colorAccent"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:statusBarScrim="@color/colorAccent"
app:title=""
app:titleEnabled="false">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:scaleType="centerCrop"
android:src="@mipmap/x001"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.7"/>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="50dp"
app:layout_collapseMode="pin"
app:popupTheme="@style/AppTheme.PopupOverlay"
app:title="">
<android.support.constraint.ConstraintLayout
android:id="@+id/appbar_show"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_arrow_back_black_24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="BiLiBiLi大講堂開播啦"
android:textColor="@android:color/white"
android:textSize="22sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</android.support.constraint.ConstraintLayout>
<android.support.constraint.ConstraintLayout
android:id="@+id/appbar_hint"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:visibility="gone">
<ImageView
android:id="@+id/appbar_hint_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_play_circle_filled_black_24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/appbar_hint_name"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="@+id/appbar_hint_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="立即播放"
android:textColor="@android:color/white"
android:textSize="22sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@+id/appbar_hint_icon"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</android.support.constraint.ConstraintLayout>
</android.support.v7.widget.Toolbar>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:id="@+id/view_nest"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="com.bloodcrown.croodnatorlayouttest2.ScrollingActivity"
tools:showIn="@layout/activity_scrolling">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin"
android:text="@string/large_text"/>
</android.support.v4.widget.NestedScrollView>
<android.support.design.widget.FloatingActionButton
android:id="@+id/view_fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="@dimen/fab_margin"
android:src="@drawable/ic_play_circle_filled_black_24dp"
app:layout_anchor="@id/app_bar"
app:layout_anchorGravity="bottom|right"/>
</android.support.design.widget.CoordinatorLayout>
public class BiliBiLiActivity extends AppCompatActivity {
// appbar展開狀態(tài)
public static final int STAET_EXPANDED = 1;
// appbar折疊狀態(tài)
public static final int STAET_COLLAPSED = -1;
// appbar中間狀態(tài)
public static final int STAET_ING = 0;
int state = 2;
// appbar 響應(yīng)滾動狀態(tài)
public static final int SCROLL_ING = -1;
// appbar 不響應(yīng)滾動狀態(tài)
public static final int SCROLL_NO = 0;
int state_scroll = SCROLL_ING;
View appBar_show;
View appBar_hint;
FloatingActionButton mFAB;
AppBarLayout mAppBar;
NestedScrollView mScrollView;
View mPlayButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bili_bi_li);
intiStateView();
appBar_show = findViewById(R.id.appbar_show);
appBar_hint = findViewById(R.id.appbar_hint);
mFAB = (FloatingActionButton) findViewById(R.id.view_fab);
mAppBar = (AppBarLayout) findViewById(R.id.app_bar);
mScrollView = (NestedScrollView) findViewById(R.id.view_nest);
mPlayButton = findViewById(R.id.appbar_hint_name);
mAppBar.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
// int totalScrollRange = appBarLayout.getTotalScrollRange();
// Log.d("AAA", "total:" + totalScrollRange + "/Offset:" + verticalOffset);
verticalOffset = Math.abs(verticalOffset);
// 初始展開狀態(tài)
if (verticalOffset == 0) {
if (state != STAET_EXPANDED) {
// 是展開狀態(tài),重置標記為展開,顯示 appbar 布局控件
state = STAET_EXPANDED;
appBar_show.setVisibility(View.VISIBLE);
appBar_hint.setVisibility(View.GONE);
}
return;
}
// 折疊狀態(tài)
if (verticalOffset >= appBarLayout.getTotalScrollRange()) {
if (state != STAET_COLLAPSED) {
// 是折疊狀態(tài),重置標記為折疊,顯示 appbar 布局控件
state = STAET_COLLAPSED;
appBar_hint.setVisibility(View.VISIBLE);
appBar_show.setVisibility(View.GONE);
}
return;
}
// 中間狀態(tài)
if (state != STAET_ING) {
// 是中間狀態(tài),重置標記為ing,顯示 appbar 布局控件
state = STAET_ING;
appBar_show.setVisibility(View.VISIBLE);
appBar_hint.setVisibility(View.GONE);
}
}
});
mFAB.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (state == STAET_EXPANDED) {
if (state_scroll == SCROLL_ING) {
// 取消滾動控件的嵌套滾動
mScrollView.setNestedScrollingEnabled(false);
state_scroll = SCROLL_NO;
} else if (state_scroll == SCROLL_NO) {
mScrollView.setNestedScrollingEnabled(true);
state_scroll = SCROLL_ING;
}
}
}
});
mPlayButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (state == STAET_COLLAPSED) {
// 處于折疊狀態(tài)時才能玩
mAppBar.setExpanded(true);
state = STAET_EXPANDED;
}
}
});
}
private void intiStateView() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WindowManager.LayoutParams layoutParams = getWindow().getAttributes();
layoutParams.flags = (layoutParams.flags | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
}