原帖: 看工秩,這個(gè)工具欄能伸縮折疊——Android CollapsingToolbarLayout使用介紹
廢話太多了, 我拷貝過來改改當(dāng)作筆記.
一打掘、相關(guān)基礎(chǔ)屬性介紹
Android studio中有一個(gè)Activity模板叫ScrollingActivity,它實(shí)現(xiàn)的就是簡(jiǎn)單的可折疊工具欄
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是一種支持響應(yīng)滾動(dòng)手勢(shì)的app bar布局(比如工具欄滾出或滾入屏幕),CollapsingToolbarLayout則是專門用來實(shí)現(xiàn)子布局內(nèi)不同元素響應(yīng)滾動(dòng)細(xì)節(jié)的布局鉴竭。
與AppBarLayout組合的滾動(dòng)布局(Recyclerview、NestedScrollView等)需要設(shè)置app:layout_behavior="@string/appbar_scrolling_view_behavior"(上面代碼中NestedScrollView控件所設(shè)置的)岸浑。沒有設(shè)置的話搏存,AppBarLayout將不會(huì)響應(yīng)滾動(dòng)布局的滾動(dòng)事件。
CollapsingToolbarLayout和ScrollView一起使用會(huì)有滑動(dòng)bug矢洲,注意要使用NestedScrollView來替代ScrollView璧眠。
AppBarLayout的子布局有5種滾動(dòng)標(biāo)識(shí)(就是上面代碼CollapsingToolbarLayout中配置的app:layout_scrollFlags屬性):
scroll:
將此布局和滾動(dòng)時(shí)間關(guān)聯(lián)。這個(gè)標(biāo)識(shí)要設(shè)置在其他標(biāo)識(shí)之前,沒有這個(gè)標(biāo)識(shí)則布局不會(huì)滾動(dòng)且其他標(biāo)識(shí)設(shè)置無效责静。enterAlways:
任何向下滾動(dòng)操作都會(huì)使此布局可見袁滥。這個(gè)標(biāo)識(shí)通常被稱為“快速返回”模式。enterAlwaysCollapsed:
假設(shè)你定義了一個(gè)最小高度(minHeight)同時(shí)enterAlways也定義了灾螃,那么view將在到達(dá)這個(gè)最小高度的時(shí)候開始顯示题翻,并且從這個(gè)時(shí)候開始慢慢展開,當(dāng)滾動(dòng)到頂部的時(shí)候展開完腰鬼。exitUntilCollapsed:
當(dāng)你定義了一個(gè)minHeight嵌赠,此布局將在滾動(dòng)到達(dá)這個(gè)最小高度的時(shí)候折疊。snap:
當(dāng)一個(gè)滾動(dòng)事件結(jié)束熄赡,如果視圖是部分可見的姜挺,那么它將被滾動(dòng)到收縮或展開。例如彼硫,如果視圖只有底部25%顯示炊豪,它將折疊。相反乌助,如果它的底部75%可見溜在,那么它將完全展開。
CollapsingToolbarLayout可以通過app:contentScrim設(shè)置折疊時(shí)工具欄布局的顏色他托,通過app:statusBarScrim設(shè)置折疊時(shí)狀態(tài)欄的顏色掖肋。默認(rèn)contentScrim是colorPrimary的色值,statusBarScrim是colorPrimaryDark的色值赏参。這個(gè)后面會(huì)用到志笼。
CollapsingToolbarLayout的子布局有3種折疊模式(Toolbar中設(shè)置的app:layout_collapseMode)
off:
這個(gè)是默認(rèn)屬性,布局將正常顯示把篓,沒有折疊的行為纫溃。pin:
CollapsingToolbarLayout折疊后,此布局將固定在頂部韧掩。parallax:
CollapsingToolbarLayout折疊時(shí)紊浩,此布局也會(huì)有視差折疊效果。
當(dāng)CollapsingToolbarLayout的子布局設(shè)置了parallax模式時(shí)疗锐,我們還可以通過app:layout_collapseParallaxMultiplier設(shè)置視差滾動(dòng)因子坊谁,值為:0~1。
FloatingActionButton這個(gè)控件通過app:layout_anchor這個(gè)設(shè)置錨定在了AppBarLayout下方滑臊。FloatingActionButton源碼中有一個(gè)Behavior方法口芍,當(dāng)AppBarLayout收縮時(shí),F(xiàn)loatingActionButton就會(huì)跟著做出相應(yīng)變化雇卷。
二鬓椭、模仿bilibili客戶端視頻詳情頁
我們先對(duì)原界面分析一下颠猴。
界面初始,CollapsingToolbarLayout是展開狀態(tài)小染,顯示的是視頻封面翘瓮。我們向上滾動(dòng)界面,CollapsingToolbarLayout收縮氧映。當(dāng)AppBarLayout完全折疊的時(shí)候視頻av號(hào)隱藏春畔,顯示出來一個(gè)小電視圖標(biāo)和“立即播放”,點(diǎn)擊則使AppBarLayout完全展開岛都,CollapsingToolbarLayout子布局由ImageView切換為視頻彈幕播放器律姨。
來我們先看修改完成的布局。
<?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站的“少女粉”臼疫,播放的圖標(biāo)是從網(wǎng)上找的择份。
<color name="colorPrimary">#FA7199</color>
因?yàn)槲覀円獙?shí)現(xiàn)沉浸式狀態(tài)欄,所以就需要先把整個(gè)activity設(shè)置成狀態(tài)欄透明模式烫堤。然后在布局文件中荣赶,把CollapsingToolbarLayout里要實(shí)現(xiàn)沉浸式的控件設(shè)置上android:fitsSystemWindows="true",如果沒有設(shè)置鸽斟,則子布局會(huì)位于狀態(tài)欄下方拔创,未延伸至狀態(tài)欄。
布局并不算復(fù)雜富蓄,接下來先實(shí)現(xiàn)無彈幕播放時(shí)的功能,剩燥。
我們需要監(jiān)聽CollapsingToolbarLayout的折疊、展開狀態(tài)立倍。唉我去灭红,官方并沒有提供現(xiàn)成的方法(⊙_⊙?)口注。
查看源碼变擒,可以看到CollapsingToolbarLayout是通過實(shí)現(xiàn)AppBarLayout的OnOffsetChangedListener接口,根據(jù)AppBarLayout的偏移來實(shí)現(xiàn)子布局和title的視差移動(dòng)以及ContentScrim和StatusBarScrim的顯示寝志。那么我們也可以通過調(diào)用AppBarLayout的addOnOffsetChangedListener方法監(jiān)聽AppBarLayout的位移娇斑,判斷CollapsingToolbarLayout的狀態(tài)。
先寫一個(gè)枚舉定義出CollapsingToolbarLayout展開材部、折疊悠菜、中間,這三種狀態(tài)败富。
private CollapsingToolbarLayoutState state;
private enum CollapsingToolbarLayoutState {
EXPANDED,
COLLAPSED,
INTERNEDIATE
}
接下來對(duì)AppBarLayout進(jìn)行監(jiān)聽,判斷CollapsingToolbarLayout的狀態(tài)并實(shí)現(xiàn)相應(yīng)的邏輯摩窃。
為了讓大家對(duì)狀態(tài)看著更直觀兽叮,我在修改狀態(tài)值的時(shí)候把title一起進(jìn)行了修改芬骄。
使用CollapsingToolbarLayout的時(shí)候要注意,在完成CollapsingToolbarLayout設(shè)置之后再調(diào)用Toolbar的setTitle()等方法將沒有效果鹦聪,我們需要改為調(diào)用CollapsingToolbarLayout的setTitle()等方法來對(duì)工具欄進(jìn)行修改账阻。(具體原因各位親去看下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;//修改狀態(tài)標(biāo)記為展開
collapsingToolbarLayout.setTitle("EXPANDED");//設(shè)置title為EXPANDED
}
} else if (Math.abs(verticalOffset) >= appBarLayout.getTotalScrollRange()) {
if (state != CollapsingToolbarLayoutState.COLLAPSED) {
collapsingToolbarLayout.setTitle("");//設(shè)置title不顯示
playButton.setVisibility(View.VISIBLE);//隱藏播放按鈕
state = CollapsingToolbarLayoutState.COLLAPSED;//修改狀態(tài)標(biāo)記為折疊
}
} else {
if (state != CollapsingToolbarLayoutState.INTERNEDIATE) {
if(state == CollapsingToolbarLayoutState.COLLAPSED){
playButton.setVisibility(View.GONE);//由折疊變?yōu)橹虚g狀態(tài)時(shí)隱藏播放按鈕
}
collapsingToolbarLayout.setTitle("INTERNEDIATE");//設(shè)置title為INTERNEDIATE
state = CollapsingToolbarLayoutState.INTERNEDIATE;//修改狀態(tài)標(biāo)記為中間
}
}
}
});
然后對(duì)播放按鈕設(shè)置監(jiān)聽泽本,點(diǎn)擊則調(diào)用AppBarLayout的setExpanded(true)方法使工具欄展開淘太。
CollapsingToolbarLayout狀態(tài)監(jiān)聽演示.gif
嗶哩嗶哩客戶端的title是固定不動(dòng)的,可以調(diào)用CollapsingToolbarLayout的setTitleEnabled(false)方法實(shí)現(xiàn)规丽。
視頻播放時(shí)蒲牧,調(diào)用 NestedScrollView的setNestedScrollingEnabled(false)方法可以使AppBarLayout不響應(yīng)滾動(dòng)事件。
細(xì)心的朋友可能發(fā)現(xiàn)了嗶哩嗶哩客戶端為了避免視頻封面圖片顏色過淺影響狀態(tài)欄信息的顯示赌莺,加了一個(gè)漸變的不透明層冰抢。
實(shí)現(xiàn)漸變遮罩層很簡(jiǎn)單。先在res/drawable文件夾下新建了一個(gè)名為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節(jié)點(diǎn)中挎扰,可以通過android:shape來設(shè)置形狀,默認(rèn)是矩形巢音。
gradient節(jié)點(diǎn)中angle的值270是從上到下遵倦,0是從左到右,90是從下到上官撼。
起始顏色#33000000是20%不透明度的黑色梧躺,#00000000表示全透明。
然后在CollapsingToolbarLayout里的ImageView代碼下面加上一個(gè)自定義view歧寺,背景設(shè)置為上面的漸變效果燥狰。
<View
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="@drawable/gradient"
android:fitsSystemWindows="true"
/>
一般狀態(tài)欄的高度大概在20dp左右,我為了讓漸變效果比較自然斜筐,并且不過多影響圖(mei)片(zi),把高度設(shè)置成了40dp龙致。(狀態(tài)欄能看清了,妹子臉也沒黑顷链,挺好 (?? . ??)∧看)
有無漸變遮罩層的對(duì)比
三.CollapsingToolbarLayout與TabLayout
CollapsingToolbarLayout與TabLayout組合使用的效果也不錯(cuò)。
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沒有設(shè)置app:layout_collapseMode嗤练,在CollapsingToolbarLayout收縮時(shí)就不會(huì)消失榛了。
CollapsingToolbarLayout收縮時(shí)的高度是Toolbar的高度,所以我們需要把Toolbar的高度增加煞抬,給TabLayout留出位置霜大,這樣收縮后TabLayout就不會(huì)和Toolbar重疊。
Toolbar的高度增加革答,title會(huì)相應(yīng)下移战坤。android:gravity="top"方法使Toolbar的title位于Toolbar的上方曙强,然后通過app:titleMarginTop調(diào)整下title距頂部高度,這樣Toolbar就和原來顯示的一樣了途茫。
CollapsingToolbarLayout還可以和Palette搭配使用碟嘴,但是我感覺在實(shí)際使用中有些坑,因?yàn)镃ollapsingToolbarLayout中的圖片不確定囊卜,Palette從圖片中獲取到的色彩很可能不是你想要的娜扇。
感興趣的朋友可以自己查下Palette的用法。