標籤:size 1.0 螢幕 start tin snap tun 跳過 tar
我非常喜歡Material Design裡摺疊工具列的效果,bilibili Android用戶端視頻詳情頁就是採用的這種設計。這篇文章的第二部分我們就通過簡單的模仿bilibili視頻詳情頁的實現來瞭解下CollapsingToolbarLayout的使用。文章的第三部分介紹了CollapsingToolbarLayout與TabLayout的組合使用。
有基礎的朋友可以直接跳過第一部分。
一、相關基礎屬性介紹
Android studio中有一個Activity模板叫ScrollingActivity,它實現的就是簡單的可摺疊工具列,我們將此模板添加到項目中。
ScrollingActivity的布局代碼如下
<?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則是專門用來實現子布局內不同元素響應滾動細節的布局。
與AppBarLayout組合的滾動布局(Recyclerview、NestedScrollView等)需要設定app:layout_behavior=”@string/appbar_scrolling_view_behavior”(上面代碼中NestedScrollView控制項所設定的)。沒有設定的話,AppBarLayout將不會響應滾動布局的滾動事件。
CollapsingToolbarLayout和ScrollView一起使用會有滑動bug,注意要使用NestedScrollView來替代ScrollView。
AppBarLayout的子布局有5種滾動標識(就是上面代碼CollapsingToolbarLayout中配置的app:layout_scrollFlags屬性):
- scroll:將此布局和滾動時間關聯。這個標識要設定在其他標識之前,沒有這個標識則布局不會滾動且其他標識設定無效。
- enterAlways:任何向下滾動操作都會使此布局可見。這個標識通常被稱為“快速返回”模式。
- enterAlwaysCollapsed:假設你定義了一個最小高度(minHeight)同時enterAlways也定義了,那麼view將在到達這個最小高度的時候開始顯示,並且從這個時候開始慢慢展開,當滾動到頂部的時候展開完。
- exitUntilCollapsed:當你定義了一個minHeight,此布局將在滾動到達這個最小高度的時候摺疊。
- snap:當一個滾動事件結束,如果視圖是部分可見的,那麼它將被滾動到收縮或展開。例如,如果視圖只有底部25%顯示,它將摺疊。相反,如果它的底部75%可見,那麼它將完全展開。
CollapsingToolbarLayout可以通過app:contentScrim設定摺疊時工具列布局的顏色,通過app:statusBarScrim設定摺疊時狀態列的顏色。預設contentScrim是colorPrimary的色值,statusBarScrim是colorPrimaryDark的色值。這個後面會用到。
CollapsingToolbarLayout的子布局有3種摺疊模式(Toolbar中設定的app:layout_collapseMode)
- off:這個是預設屬性,布局將正常顯示,沒有摺疊的行為。
- pin:CollapsingToolbarLayout摺疊後,此布局將固定在頂部。
- parallax:CollapsingToolbarLayout摺疊時,此布局也會有視差摺疊效果。
當CollapsingToolbarLayout的子布局設定了parallax模式時,我們還可以通過app:layout_collapseParallaxMultiplier設定視差滾動因子,值為:0~1。
FloatingActionButton這個控制項通過app:layout_anchor這個設定錨定在了AppBarLayout下方。FloatingActionButton源碼中有一個Behavior方法,當AppBarLayout收縮時,FloatingActionButton就會跟著做出相應變化。關於CoordinatorLayout和Behavior,我下一篇文章會和大家一起學習。
這一堆屬性看著有點煩,大家可以建立一個ScrollingActivity模板去實驗一下玩玩。
二、模仿bilibili用戶端視頻詳情頁
我們先對原介面分析一下。
介面初始,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)方法使工具列展開。
嗶哩嗶哩用戶端的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。(狀態列能看清了,妹子臉也沒黑,挺好 (?? . ??) )
我省略了彈幕播放的相關實現,接下來只要在播放按鈕監聽中寫出封面圖片的隱藏、視頻和彈幕彈幕控制項的顯示初始化及播放邏輯,在AppBarLayout的三種狀態監聽中根據是否視頻在播放寫出其他相應邏輯就好了,感興趣的朋友可以下載嗶哩嗶哩的“烈焰彈幕使”源碼DanmakuFlameMaster玩玩。
B網站擊追番或投硬幣後會出現一個類似Snackbar的提示控制項,可以通過我上一篇文章沒時間解釋了,快使用Snackbar!——Android Snackbar花式使用指南來實現,歡迎感興趣的朋友去看看。
真的不是我懶得上代碼了,真的…(基友:趕緊的,開黑了。 我:等等我,馬上來!\(≧▽≦)/)
三.CollapsingToolbarLayout與TabLayout
CollapsingToolbarLayout與TabLayout組合使用的效果也不錯。
來看下CollapsingToolbarLayout裡的代碼
<android.support.design.widget.CollapsingToolbarLayout android:id="@+id/collapsingtoolbar" android:layout_width="match_parent" android:layout_height="match_parent" app:titleEnabled="false" 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"/> <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" app:titleMarginTop="15dp" android:gravity="top" app:layout_collapseMode="pin" app:title="hello" app:popupTheme="@style/AppTheme.PopupOverlay" /> <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>
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的用法。
【轉】Material Design 摺疊效果 Toolbar CollapsingToolbarLayout AppBarLayout