在許多App中看到, toolbar有收縮和擴(kuò)展的效果, 例如:
要實現(xiàn)這樣的效果, 需要用到:
CoordinatorLayout和AppbarLayout的配合, 以及實現(xiàn)了NestedScrollView的布局或控件.
AppbarLayout是一種支持響應(yīng)滾動手勢的app bar布局, CollapsingToolbarLayout則是專門用來實現(xiàn)子布局內(nèi)不同元素響應(yīng)滾動細(xì)節(jié)的布局.
與AppbarLayout組合的滾動布局(RecyclerView, NestedScrollView等),需要設(shè)置 app:layout_behavior = "@string/appbar_scrolling_view_behavior" .沒有設(shè)置的話, AppbarLayout將不會響應(yīng)滾動布局的滾動事件.
我們回到再前面一章"Toolbar的使用", 將布局改動如下:
<?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"
tools:context="com.truly.mytoolbar.MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:layout_scrollFlags="scroll"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:title="Title" />
</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:id="@+id/tv_content"
android:layout_margin="16dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:lineSpacingMultiplier="2"
android:text="@string/textContent" />
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
先看下效果再來解釋為什么.
可以看到,
- 隨著文本往上滾動, 頂部的toolbar也往上滾動, 直到消失.
- 隨著文本往下滾動, 一直滾到文本的第一行露出來, toolbar也逐漸露出來
解釋:
從上面的布局中可以看到, 其實在整個父布局CoordinatorLayout下面, 是有2個子布局
- AppbarLayout
- NestedScrollView
NestedScrollView先放一放, 我們來看AppbarLayout.
AppBarLayout 繼承自LinearLayout洪乍,布局方向為垂直方向。所以你可以把它當(dāng)成垂直布局的LinearLayout來使用俺叭。AppBarLayout是在LinearLayou上加了一些材料設(shè)計的概念,它可以讓你定制當(dāng)某個可滾動View的滾動手勢發(fā)生變化時房蝉,其內(nèi)部的子View實現(xiàn)何種動作。
注意:
上面提到的"某個可滾動View", 可以理解為某個ScrollView. 就是說,當(dāng)某個ScrollView發(fā)生滾動時风皿,你可以定制你的“頂部欄”應(yīng)該執(zhí)行哪些動作(如跟著一起滾動龟虎、保持不動等等)璃谨。
這里某個ScrollView就是NestedScrollView或者實現(xiàn)了NestedScrollView機(jī)制的其它控件, 如RecyclerView. 它有一個布局行為Layout_Behavior:
app:layout_behavior="@string/appbar_scrolling_view_behavior"
這是一個系統(tǒng)behavior, 從字面意思就可以看到, 是為appbar設(shè)置滾動動作的一個behavior. 沒有這個屬性的話, Appbar就是死的, 有了它就有了靈魂.
我們可以通過給Appbar下的子View添加app:layout_scrollFlags來設(shè)置各子View執(zhí)行的動作. scrollFlags可以設(shè)置的動作如下:
(1) scroll: 值設(shè)為scroll的View會跟隨滾動事件一起發(fā)生移動。就是當(dāng)指定的ScrollView發(fā)生滾動時鲤妥,該View也跟隨一起滾動佳吞,就好像這個View也是屬于這個ScrollView一樣。
上面這個效果就是設(shè)置了scroll之后的.
(2) enterAlways: 值設(shè)為enterAlways的View,當(dāng)任何時候ScrollView往下滾動時棉安,該View會直接往下滾動底扳。而不用考慮ScrollView是否在滾動到最頂部還是哪里.
我們把layout_scrollFlags改動如下:
app:layout_scrollFlags="scroll|enterAlways"
效果如下:
(3) exitUntilCollapsed:值設(shè)為exitUntilCollapsed的View,當(dāng)這個View要往上逐漸“消逝”時贡耽,會一直往上滑動衷模,直到剩下的的高度達(dá)到它的最小高度后,再響應(yīng)ScrollView的內(nèi)部滑動事件蒲赂。
怎么理解呢阱冶?簡單解釋:在ScrollView往上滑動時,首先是View把滑動事件“奪走”滥嘴,由View去執(zhí)行滑動木蹬,直到滑動最小高度后,把這個滑動事件“還”回去氏涩,讓ScrollView內(nèi)部去上滑届囚。
把屬性改下再看效果
<android.support.v7.widget.Toolbar
...
android:layout_height="?attr/actionBarSize"
android:minHeight="20dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
/>
(4) enterAlwaysCollapsed:是enterAlways的附加選項,一般跟enterAlways一起使用是尖,它是指意系,View在往下“出現(xiàn)”的時候,首先是enterAlways效果饺汹,當(dāng)View的高度達(dá)到最小高度時蛔添,View就暫時不去往下滾動,直到ScrollView滑動到頂部不再滑動時兜辞,View再繼續(xù)往下滑動迎瞧,直到滑到View的頂部結(jié)束
這個得把高度加大點才好實驗. 來看:
<android.support.v7.widget.Toolbar
...
android:layout_height="200dp"
android:minHeight="?attr/actionBarSize"
app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed"
</android.support.design.widget.AppBarLayout>
Attention:
其實toolbar的默認(rèn)最小高度minHeight就是"?attr/actionBarSize" , 很多時候可以不用設(shè)置. 而且從圖上可以看出, 其實這里有個缺陷, 就是title的位置和toolbar上的圖標(biāo)行脫離了, 即使在布局里添加了 android:gravity="bottom|start", 在toolbar滾動的時候, title還在, 圖標(biāo)滾動到隱藏了.
后面講解的CollapsingToolbarLayout可以解決這個問題, 這里先丟出來.
(5) snap:簡單理解,就是Child View滾動比例的一個吸附效果逸吵。也就是說凶硅,Child View不會存在局部顯示的情況,滾動Child View的部分高度扫皱,當(dāng)我們松開手指時足绅,Child View要么向上全部滾出屏幕捷绑,要么向下全部滾進(jìn)屏幕,有點類似ViewPager的左右滑動
引入CollapsingToolbarLayout
CollapsingToolbarLayout是用來對Toolbar進(jìn)行再次包裝的ViewGroup氢妈,主要是用于實現(xiàn)折疊(其實就是看起來像伸縮~)的App Bar效果粹污。它需要放在AppBarLayout布局里面,并且作為AppBarLayout的直接子View首量。CollapsingToolbarLayout主要包括幾個功能(參照了官方網(wǎng)站上內(nèi)容壮吩,略加自己的理解進(jìn)行解釋):
(1) 折疊Title(Collapsing title):當(dāng)布局內(nèi)容全部顯示出來時,title是最大的加缘,但是隨著View逐步移出屏幕頂部鸭叙,title變得越來越小。你可以通過調(diào)用setTitle方法來設(shè)置title生百。
(2)內(nèi)容紗布(Content scrim):根據(jù)滾動的位置是否到達(dá)一個閥值递雀,來決定是否對View“蓋上紗布”柄延∈唇可以通過setContentScrim(Drawable)來設(shè)置紗布的圖片. 默認(rèn)contentScrim是colorPrimary的色值
(3)狀態(tài)欄紗布(Status bar scrim):根據(jù)滾動位置是否到達(dá)一個閥值決定是否對狀態(tài)欄“蓋上紗布”,你可以通過setStatusBarScrim(Drawable)來設(shè)置紗布圖片搜吧,但是只能在LOLLIPOP設(shè)備上面有作用市俊。默認(rèn)statusBarScrim是colorPrimaryDark的色值.
(4)視差滾動子View(Parallax scrolling children): 子View可以選擇在當(dāng)前的布局當(dāng)時是否以“視差”的方式來跟隨滾動。(PS:其實就是讓這個View的滾動的速度比其他正常滾動的View速度稍微慢一點)滤奈。將布局參數(shù)app:layout_collapseMode設(shè)為parallax
(5)將子View位置固定(Pinned position children):子View可以選擇是否在全局空間上固定位置摆昧,這對于Toolbar來說非常有用,因為當(dāng)布局在移動時蜒程,可以將Toolbar固定位置而不受移動的影響绅你。 將app:layout_collapseMode設(shè)為pin。
我們來更改一下布局:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
...>
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="150dp">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_collapseMode="parallax"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:title="Title" />
</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:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="16dp"
android:lineSpacingMultiplier="2"
android:text="@string/textContent" />
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
可以看到, 我們把原本屬于toolbar的幾個屬性移到了CollapsingToolbarLayout上. 分別是:
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
同時給toolbar增加了一個折疊模式屬性
app:layout_collapseMode="parallax"
我們來看下效果:
嗯嗯, 折疊模式不對, toolbar的頂部圖標(biāo)沒了. 我們改下折疊模式:
app:layout_collapseMode="pin"
再看效果:
我們把scrollFlags屬性改下, 看下對比:
app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed"
效果還是蠻不錯的, 有了點Google Material Design的感覺了.
上面說CollapsingToolbarLayout是個ViewGroup, 那么肯定還可以添加控件. 那么我們在里面添加一個ImageView來看看. 更改布局如下:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
...>
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="200dp">
<android.support.design.widget.CollapsingToolbarLayout
...
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@drawable/darkbg"
app:layout_collapseMode="parallax" />
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_collapseMode="pin"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:title="Title" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
...
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<TextView
... />
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
來看下效果:
嗯, 有了點意思, 但不美觀, 上部的toolbar和圖片不協(xié)調(diào). toolbar應(yīng)該有默認(rèn)的背景屬性, 我們?nèi)サ羲纯?
<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/ThemeOverlay.AppCompat.Light"
app:title="Title" />
再看下效果:
這次真的不錯哦, 已經(jīng)和很多大公司的app相像了. 但是為什么去掉toolbar的background就可以得到透明背景呢? 說句實話, 沒找到原因.
不過我們沒有給CollapsingToolbarLayout設(shè)置contentScrim屬性哦, 給它加個屬性看看.
<android.support.design.widget.CollapsingToolbarLayout
...
app:contentScrim="?attr/colorPrimary"
...>
嗯嗯, 好像還不如沒設(shè)置這個屬性好呢.
什么時候需要contentScrim屬性呢?
因為這個布局里面給CollapsingToolbarLayout的layout_scrollFlags設(shè)置的是 "scroll|enterAlways|enterAlwaysCollapsed" , toolbar會全部消失的, 所以感覺不是很美觀. 如果將layout_scrollFlags屬性改為 "scroll|exitUntilCollapsed" , 效果會好點, 適合toolbar還是需要展示的場合.
不管怎么樣, 先去掉contentScrim屬性吧.
目前有很多APP比較喜歡采用沉浸式設(shè)計, 簡單點說就是將狀態(tài)欄和導(dǎo)航欄都設(shè)置成透明或半透明的.
我們來把狀態(tài)欄statusBar設(shè)置成透明. 在style主題中的AppTheme里增加一條:
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
...
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
在布局里面, 將ImageView和所有它上面的父View都添加fitsSystemWindows屬性.
<?xml version="1.0" encoding="utf-8"?>
<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" />
<android.support.v7.widget.Toolbar
... />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
...>
<TextView
... />
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
最后來看下效果:
其實還可以在CollapsingToolbarLayout里設(shè)置statusBarScrim為透明色, 不過有點問題, 最頂部的toolbar沒有完全隱藏, 還留了一點尾巴.
難道就這個屬性就沒用嗎? 我們把layout_scrollFlags改成 "scroll|exitUntilCollapsed" 看看:
這個時候toolbar不用隱藏, 所以還是美美的.
AppbarLayout整個做成沉浸式之后, 狀態(tài)欄的圖標(biāo)可能會受到封面圖片顏色過淺的影響, 可以給其加一個漸變的不透明層.
漸變遮罩設(shè)置方法:
在res/drawable文件夾下新建一個名為status_gradient的xml資源文件, 代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:angle="270"
android:endColor="@android:color/transparent"
android:startColor="#CC000000" />
<!-- shape節(jié)點中, 可以通過android:shape來設(shè)置形狀, 默認(rèn)是矩形.
gradient節(jié)點中angle的值270是從上到下昭躺,0是從左到右忌锯,90是從下到上。
此處的效果就是從下向上, 顏色逐漸由純透明慢慢變成黑透色-->
</shape>
布局中, 在ImageView下面增加一個View, 背景設(shè)為上面的漸變遮罩.
<!-- 在頂部增加一個漸變遮罩, 防止出現(xiàn)status bar 狀態(tài)欄看不清 -->
<View
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="@drawable/status_gradient"
app:layout_collapseMode="pin"
android:fitsSystemWindows="true" />
給遮罩設(shè)置折疊模式: app:layout_collapseMode="pin" , 折疊到頂部后定住. 來看下效果.
上圖是展開狀態(tài)的對比, 后面的是沒有添加遮罩的效果, 前面是添加了遮罩的效果. 下圖是添加了遮罩折疊后的效果. 有點黑暗系影片的感覺哦.
FloatingActionButton再次表演
作為Google Material Design的一個重要控件, FloatingActionButton怎么可能不在AppbarLayout中起點作用呢. 我們在布局中加一個懸浮按鈕, 讓它的錨點掛載Appbar的右下角. 這樣這個懸浮按鈕就和Appbar關(guān)聯(lián)起來了.
<android.support.design.widget.CoordinatorLayout
...>
<android.support.design.widget.AppBarLayout
...
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
...
</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="16dp"
android:src="@drawable/ic_share_white_24dp"
android:elevation="4dp"
app:pressedTranslationZ="16dp"
app:rippleColor="@android:color/white"
app:layout_anchor="@id/appbar"
app:layout_anchorGravity="bottom|end"/>
</android.support.design.widget.CoordinatorLayout>
我們來看下效果.
好吧, 美美的Toolbar完成了, 有點Google Material Design撲面而來的感覺了.
這篇文章已經(jīng)很長了, 還有些內(nèi)容就不放進(jìn)來了, 后面陸續(xù)完善.
借鑒了很多資料, 寫的時候忘了記錄下來, 如對您有損, 請聯(lián)系我進(jìn)行刪除或更改. 致歉!