Android CollapsingToolbarLayout使用介紹

我很是喜歡Material Design裏摺疊工具欄的效果,bilibili Android客戶端視頻詳情頁就是採用的這種設計。這篇文章的第二部分咱們就經過簡單的模仿bilibili視頻詳情頁的實現來了解下CollapsingToolbarLayout的使用。文章的第三部分介紹了CollapsingToolbarLayout與TabLayout的組合使用。php

有基礎的朋友能夠直接跳過第一部分。java

1、相關基礎屬性介紹

Android studio中有一個Activity模板叫ScrollingActivity,它實現的就是簡單的可摺疊工具欄,咱們將此模板添加到項目中。android


ScrollingActivity.gif

ScrollingActivity的佈局代碼以下git

<?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" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true"> <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 android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" > <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" android:src="@android:drawable/ic_dialog_email" app:layout_anchor="@id/app_bar" app:layout_anchorGravity="bottom|end" /> </android.support.design.widget.CoordinatorLayout> 

AppBarLayout是一種支持響應滾動手勢的app bar佈局(好比工具欄滾出或滾入屏幕),CollapsingToolbarLayout則是專門用來實現子佈局內不一樣元素響應滾動細節的佈局。github

與AppBarLayout組合的滾動佈局(Recyclerview、NestedScrollView等)須要設置app:layout_behavior="@string/appbar_scrolling_view_behavior"(上面代碼中NestedScrollView控件所設置的)。沒有設置的話,AppBarLayout將不會響應滾動佈局的滾動事件。app

CollapsingToolbarLayout和ScrollView一塊兒使用會有滑動bug,注意要使用NestedScrollView來替代ScrollView。ide

AppBarLayout的子佈局有5種滾動標識(就是上面代碼CollapsingToolbarLayout中配置的app:layout_scrollFlags屬性):工具

  1. scroll:將此佈局和滾動時間關聯。這個標識要設置在其餘標識以前,沒有這個標識則佈局不會滾動且其餘標識設置無效。
  2. enterAlways:任何向下滾動操做都會使此佈局可見。這個標識一般被稱爲「快速返回」模式。
  3. enterAlwaysCollapsed:假設你定義了一個最小高度(minHeight)同時enterAlways也定義了,那麼view將在到達這個最小高度的時候開始顯示,而且從這個時候開始慢慢展開,當滾動到頂部的時候展開完。
  4. exitUntilCollapsed:當你定義了一個minHeight,此佈局將在滾動到達這個最小高度的時候摺疊。
  5. snap:當一個滾動事件結束,若是視圖是部分可見的,那麼它將被滾動到收縮或展開。例如,若是視圖只有底部25%顯示,它將摺疊。相反,若是它的底部75%可見,那麼它將徹底展開。

CollapsingToolbarLayout能夠經過app:contentScrim設置摺疊時工具欄佈局的顏色,經過app:statusBarScrim設置摺疊時狀態欄的顏色。默認contentScrim是colorPrimary的色值,statusBarScrim是colorPrimaryDark的色值。這個後面會用到。佈局

CollapsingToolbarLayout的子佈局有3種摺疊模式(Toolbar中設置的app:layout_collapseMode)學習

  1. off:這個是默認屬性,佈局將正常顯示,沒有摺疊的行爲。
  2. pin:CollapsingToolbarLayout摺疊後,此佈局將固定在頂部。
  3. parallax:CollapsingToolbarLayout摺疊時,此佈局也會有視差摺疊效果。

當CollapsingToolbarLayout的子佈局設置了parallax模式時,咱們還能夠經過app:layout_collapseParallaxMultiplier設置視差滾動因子,值爲:0~1。

FloatingActionButton這個控件經過app:layout_anchor這個設置錨定在了AppBarLayout下方。FloatingActionButton源碼中有一個Behavior方法,當AppBarLayout收縮時,FloatingActionButton就會跟着作出相應變化。關於CoordinatorLayout和Behavior,我下一篇文章會和你們一塊兒學習。

這一堆屬性看着有點煩,你們能夠新建一個ScrollingActivity模板去實驗一下玩玩。

2、模仿bilibili客戶端視頻詳情頁

咱們先對原界面分析一下。


嗶哩嗶哩Android客戶端視頻詳情頁.gif

界面初始,CollapsingToolbarLayout是展開狀態,顯示的是視頻封面。咱們向上滾動界面,CollapsingToolbarLayout收縮。當AppBarLayout徹底摺疊的時候視頻av號隱藏,顯示出來一個小電視圖標和「當即播放」,點擊則使AppBarLayout徹底展開,CollapsingToolbarLayout子佈局由ImageView切換爲視頻彈幕播放器。

額...彈幕播放器...

B站很早就開源了一個彈幕引擎,還起了個狂拽酷炫吊炸天的名字叫「烈焰彈幕使 」(一看就是二次元程序猿們的做品→_→),源碼在github上,項目名叫DanmakuFlameMaster

來咱們先看修改完成的佈局。

<?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/coordinatorLayout" 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="@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" app:contentScrim="?attr/colorPrimary" app:statusBarScrim="@android:color/transparent" app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"> <!--封面圖片--> <ImageView android:id="@+id/imageview" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" android:src="@drawable/diqiu" app:layout_collapseMode="parallax" app:layout_collapseParallaxMultiplier="0.7" android:fitsSystemWindows="true"/> <!--視頻及彈幕控件--> <FrameLayout android:id="@+id/video_danmu" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_collapseMode="parallax" app:layout_collapseParallaxMultiplier="0.7" android:fitsSystemWindows="true" android:visibility="gone"> <VideoView android:id="@+id/videoview" android:layout_width="match_parent" android:layout_height="match_parent" /> <!--嗶哩嗶哩開源的彈幕控件--> <master.flame.danmaku.ui.widget.DanmakuView android:id="@+id/danmaku" android:layout_width="match_parent" android:layout_height="match_parent" /> </FrameLayout> <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.v7.widget.ButtonBarLayout android:id="@+id/playButton" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:visibility="gone"> <ImageView android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="center_horizontal" android:src="@mipmap/ic_play_circle_filled_white_48dp"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#ffffff" android:text="當即播放" android:layout_gravity="center_vertical" /> </android.support.v7.widget.ButtonBarLayout> </android.support.v7.widget.Toolbar> </android.support.design.widget.CollapsingToolbarLayout> </android.support.design.widget.AppBarLayout> <include layout="@layout/content_scrolling" /> <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" android:src="@mipmap/ic_play_circle_filled_white_48dp" app:layout_anchor="@id/app_bar" app:layout_anchorGravity="bottom|end" /> </android.support.design.widget.CoordinatorLayout> 

我把colorPrimary的色值修改爲了B站的「少女粉」,播放的圖標是從網上找的。

<color name="colorPrimary">#FA7199</color> 

由於咱們要實現沉浸式狀態欄,因此就須要先把整個activity設置成狀態欄透明模式。而後在佈局文件中,把CollapsingToolbarLayout裏要實現沉浸式的控件設置上android:fitsSystemWindows="true",若是沒有設置,則子佈局會位於狀態欄下方,未延伸至狀態欄。

佈局並不算複雜,接下來先實現無彈幕播放時的功能,。

咱們須要監聽CollapsingToolbarLayout的摺疊、展開狀態。唉我去,官方並無提供現成的方法(⊙_⊙?)。

查看源碼,能夠看到CollapsingToolbarLayout是經過實現AppBarLayout的OnOffsetChangedListener接口,根據AppBarLayout的偏移來實現子佈局和title的視差移動以及ContentScrim和StatusBarScrim的顯示。那麼咱們也能夠經過調用AppBarLayout的addOnOffsetChangedListener方法監聽AppBarLayout的位移,判斷CollapsingToolbarLayout的狀態。

先寫一個枚舉定義出CollapsingToolbarLayout展開、摺疊、中間,這三種狀態。

private CollapsingToolbarLayoutState state; private enum CollapsingToolbarLayoutState { EXPANDED, COLLAPSED, INTERNEDIATE } 

接下來對AppBarLayout進行監聽,判斷CollapsingToolbarLayout的狀態並實現相應的邏輯。

爲了讓你們對狀態看着更直觀,我在修改狀態值的時候把title一塊兒進行了修改。

使用CollapsingToolbarLayout的時候要注意,在完成CollapsingToolbarLayout設置以後再調用Toolbar的setTitle()等方法將沒有效果,咱們須要改成調用CollapsingToolbarLayout的setTitle()等方法來對工具欄進行修改。(具體緣由各位親去看下CollapsingToolbarLayout源碼就知道了 ( ˙-˙ ) )

AppBarLayout  app_bar=(AppBarLayout)findViewById(R.id.app_bar);
    app_bar.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() { @Override public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { if (verticalOffset == 0) { if (state != CollapsingToolbarLayoutState.EXPANDED) { state = CollapsingToolbarLayoutState.EXPANDED;//修改狀態標記爲展開 collapsingToolbarLayout.setTitle("EXPANDED");//設置title爲EXPANDED } } else if (Math.abs(verticalOffset) >= appBarLayout.getTotalScrollRange()) { if (state != CollapsingToolbarLayoutState.COLLAPSED) { collapsingToolbarLayout.setTitle("");//設置title不顯示 playButton.setVisibility(View.VISIBLE);//隱藏播放按鈕 state = CollapsingToolbarLayoutState.COLLAPSED;//修改狀態標記爲摺疊 } } else { if (state != CollapsingToolbarLayoutState.INTERNEDIATE) { if(state == CollapsingToolbarLayoutState.COLLAPSED){ playButton.setVisibility(View.GONE);//由摺疊變爲中間狀態時隱藏播放按鈕 } collapsingToolbarLayout.setTitle("INTERNEDIATE");//設置title爲INTERNEDIATE state = CollapsingToolbarLayoutState.INTERNEDIATE;//修改狀態標記爲中間 } } } }); 

而後對播放按鈕設置監聽,點擊則調用AppBarLayout的setExpanded(true)方法使工具欄展開。


CollapsingToolbarLayout狀態監聽演示.gif

嗶哩嗶哩客戶端的title是固定不動的,能夠調用CollapsingToolbarLayout的setTitleEnabled(false)方法實現。

視頻播放時,調用 NestedScrollView的setNestedScrollingEnabled(false)方法可使AppBarLayout不響應滾動事件。

細心的朋友可能發現了嗶哩嗶哩客戶端爲了不視頻封面圖片顏色過淺影響狀態欄信息的顯示,加了一個漸變的不透明層。

實現漸變遮罩層很簡單。先在res/drawable文件夾下新建了一個名爲gradient的xml文件,其中代碼以下:

<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <gradient android:startColor="#33000000" android:endColor="#00000000" android:angle="270" /> </shape> 

shape節點中,能夠經過android:shape來設置形狀,默認是矩形。gradient節點中angle的值270是從上到下,0是從左到右,90是從下到上。起始顏色#33000000是20%不透明度的黑色,#00000000表示全透明。

而後在CollapsingToolbarLayout裏的ImageView代碼下面加上一個自定義view,背景設置爲上面的漸變效果。

<View android:layout_width="match_parent" android:layout_height="40dp" android:background="@drawable/gradient" android:fitsSystemWindows="true" /> 

通常狀態欄的高度大概在20dp左右,我爲了讓漸變效果比較天然,而且不過多影響圖(mei)片(zi),把高度設置成了40dp。(狀態欄能看清了,妹子臉也沒黑,挺好 (๑• . •๑) )

有無漸變遮罩層的對比.jpg

我省略了彈幕播放的相關實現,接下來只要在播放按鈕監聽中寫出封面圖片的隱藏、視頻和彈幕彈幕控件的顯示初始化及播放邏輯,在AppBarLayout的三種狀態監聽中根據是否視頻在播放寫出其餘相應邏輯就行了,感興趣的朋友能夠下載嗶哩嗶哩的「烈焰彈幕使」源碼DanmakuFlameMaster玩玩。

B站點擊追番或投硬幣後會出現一個相似Snackbar的提示控件,能夠經過我上一篇文章沒時間解釋了,快使用Snackbar!——Android Snackbar花式使用指南來實現,歡迎感興趣的朋友去看看。

模仿嗶哩嗶哩視頻詳情頁.gif

真的不是我懶得上代碼了,真的…(基友:趕忙的,開黑了。 我:等等我,立刻來!\(≧▽≦)/)

三.CollapsingToolbarLayout與TabLayout

CollapsingToolbarLayout與TabLayout組合使用的效果也不錯。


CollapsingToolbarLayout與TabLayout.gif

來看下CollapsingToolbarLayout裏的代碼

<?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" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true"> <android.support.design.widget.AppBarLayout android:id="@+id/app_bar" android:layout_width="match_parent" android:layout_height="250dp" 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" app:titleEnabled="false" android:fitsSystemWindows="true" app:contentScrim="@color/colorPrimary" app:statusBarScrim="@android:color/transparent" app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"> <ImageView android:id="@+id/imageview" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" android:adjustViewBounds="true" app:layout_collapseMode="parallax" app:layout_collapseParallaxMultiplier="0.7" android:fitsSystemWindows="true" android:src="@drawable/girl2"/> <View android:layout_width="match_parent" android:layout_height="40dp" android:background="@drawable/gradient" android:fitsSystemWindows="true" /> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="96dp" android:minHeight="?attr/actionBarSize" android:gravity="top" app:layout_collapseMode="pin" app:title="hello" app:popupTheme="@style/AppTheme.PopupOverlay" app:titleMarginTop="15dp" /> <android.support.design.widget.TabLayout android:id="@+id/tablayout" android:layout_width="match_parent" android:layout_height="45dp" android:layout_gravity="bottom" /> </android.support.design.widget.CollapsingToolbarLayout> </android.support.design.widget.AppBarLayout> <android.support.v4.view.ViewPager android:id="@+id/viewpage" android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_behavior="@string/appbar_scrolling_view_behavior"> </android.support.v4.view.ViewPager> </android.support.design.widget.CoordinatorLayout> 

TabLayout沒有設置app:layout_collapseMode,在CollapsingToolbarLayout收縮時就不會消失。

CollapsingToolbarLayout收縮時的高度是Toolbar的高度,因此咱們須要把Toolbar的高度增長,給TabLayout留出位置,這樣收縮後TabLayout就不會和Toolbar重疊。

Toolbar的高度增長,title會相應下移。android:gravity="top"方法使Toolbar的title位於Toolbar的上方,而後經過app:titleMarginTop調整下title距頂部高度,這樣Toolbar就和原來顯示的同樣了。


CollapsingToolbarLayout還能夠和Palette搭配使用,可是我感受在實際使用中有些坑,由於CollapsingToolbarLayout中的圖片不肯定,Palette從圖片中獲取到的色彩極可能不是你想要的。

感興趣的朋友能夠本身查下Palette的用法。

就是這些。 []~( ̄▽ ̄)~*

https://www.jianshu.com/p/06c0ae8d9a96
相關文章
相關標籤/搜索