1. 程式人生 > >AppbarLayout的簡單用法

AppbarLayout的簡單用法

在許多App中看到, toolbar有收縮和擴充套件的效果, 例如:

在這裡插入圖片描述

要實現這樣的效果, 需要用到:
CoordinatorLayout和AppbarLayout的配合, 以及實現了NestedScrollView的佈局或控制元件.
AppbarLayout是一種支援響應滾動手勢的app bar佈局, CollapsingToolbarLayout則是專門用來實現子佈局內不同元素響應滾動細節的佈局.
與AppbarLayout組合的滾動佈局(RecyclerView, NestedScrollView等),需要設定 app:layout_behavior = “@string/appbar_scrolling_view_behavior” .沒有設定的話, AppbarLayout將不會響應滾動佈局的滾動事件.
我們回到再前面一章"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>

先看下效果再來解釋為什麼.

在這裡插入圖片描述

appbar_2.gif

可以看到,

  • 隨著文字往上滾動, 頂部的toolbar也往上滾動, 直到消失.
  • 隨著文字往下滾動, 一直滾到文字的第一行露出來, toolbar也逐漸露出來

解釋:
從上面的佈局中可以看到, 其實在整個父佈局CoordinatorLayout下面, 是有2個子佈局

  • AppbarLayout
  • NestedScrollView

NestedScrollView先放一放, 我們來看AppbarLayout.

AppBarLayout 繼承自LinearLayout,佈局方向為垂直方向。所以你可以把它當成垂直佈局的LinearLayout來使用。AppBarLayout是在LinearLayou上加了一些材料設計的概念,它可以讓你定製當某個可滾動View的滾動手勢發生變化時,其內部的子View實現何種動作。

注意:
上面提到的"某個可滾動View", 可以理解為某個ScrollView. 就是說,當某個ScrollView發生滾動時,你可以定製你的“頂部欄”應該執行哪些動作(如跟著一起滾動、保持不動等等)。
這裡某個ScrollView就是NestedScrollView或者實現了NestedScrollView機制的其它控制元件, 如RecyclerView. 它有一個佈局行為Layout_Behavior:

app:layout_behavior="@string/appbar_scrolling_view_behavior"

這是一個系統behavior, 從字面意思就可以看到, 是為appbar設定滾動動作的一個behavior. 沒有這個屬性的話, Appbar就是死的, 有了它就有了靈魂.
我們可以通過給Appbar下的子View新增app:layout_scrollFlags來設定各子View執行的動作. scrollFlags可以設定的動作如下:

(1) scroll: 值設為scroll的View會跟隨滾動事件一起發生移動。就是當指定的ScrollView發生滾動時,該View也跟隨一起滾動,就好像這個View也是屬於這個ScrollView一樣。

上面這個效果就是設定了scroll之後的.

(2) enterAlways: 值設為enterAlways的View,當任何時候ScrollView往下滾動時,該View會直接往下滾動。而不用考慮ScrollView是否在滾動到最頂部還是哪裡.

我們把layout_scrollFlags改動如下:

app:layout_scrollFlags="scroll|enterAlways"

效果如下:

在這裡插入圖片描述

appbar_3.gif

(3) exitUntilCollapsed:值設為exitUntilCollapsed的View,當這個View要往上逐漸“消逝”時,會一直往上滑動,直到剩下的的高度達到它的最小高度後,再響應ScrollView的內部滑動事件。

怎麼理解呢?簡單解釋:在ScrollView往上滑動時,首先是View把滑動事件“奪走”,由View去執行滑動,直到滑動最小高度後,把這個滑動事件“還”回去,讓ScrollView內部去上滑。
把屬性改下再看效果

<android.support.v7.widget.Toolbar
    ...
    android:layout_height="?attr/actionBarSize"
    android:minHeight="20dp"
    app:layout_scrollFlags="scroll|exitUntilCollapsed"
/>

在這裡插入圖片描述

appbar_4.gif

(4) enterAlwaysCollapsed:是enterAlways的附加選項,一般跟enterAlways一起使用,它是指,View在往下“出現”的時候,首先是enterAlways效果,當View的高度達到最小高度時,View就暫時不去往下滾動,直到ScrollView滑動到頂部不再滑動時,View再繼續往下滑動,直到滑到View的頂部結束

這個得把高度加大點才好實驗. 來看:

<android.support.v7.widget.Toolbar
    ...
    android:layout_height="200dp"
    android:minHeight="?attr/actionBarSize"
    app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed"
</android.support.design.widget.AppBarLayout>

在這裡插入圖片描述

appbar_5.gif

Attention:
其實toolbar的預設最小高度minHeight就是"?attr/actionBarSize" , 很多時候可以不用設定. 而且從圖上可以看出, 其實這裡有個缺陷, 就是title的位置和toolbar上的圖示行脫離了, 即使在佈局裡添加了 android:gravity=“bottom|start”, 在toolbar滾動的時候, title還在, 圖示滾動到隱藏了.

在這裡插入圖片描述

image.png

後面講解的CollapsingToolbarLayout可以解決這個問題, 這裡先丟出來.

(5) snap:簡單理解,就是Child View滾動比例的一個吸附效果。也就是說,Child View不會存在區域性顯示的情況,滾動Child View的部分高度,當我們鬆開手指時,Child View要麼向上全部滾出螢幕,要麼向下全部滾進螢幕,有點類似ViewPager的左右滑動

在這裡插入圖片描述

appbar_6.gif

引入CollapsingToolbarLayout
CollapsingToolbarLayout是用來對Toolbar進行再次包裝的ViewGroup,主要是用於實現摺疊(其實就是看起來像伸縮~)的App Bar效果。它需要放在AppBarLayout佈局裡面,並且作為AppBarLayout的直接子View。CollapsingToolbarLayout主要包括幾個功能(參照了官方網站上內容,略加自己的理解進行解釋):

(1) 摺疊Title(Collapsing title):當佈局內容全部顯示出來時,title是最大的,但是隨著View逐步移出螢幕頂部,title變得越來越小。你可以通過呼叫setTitle方法來設定title。

(2)內容紗布(Content scrim):根據滾動的位置是否到達一個閥值,來決定是否對View“蓋上紗布”。可以通過setContentScrim(Drawable)來設定紗布的圖片. 預設contentScrim是colorPrimary的色值

(3)狀態列紗布(Status bar scrim):根據滾動位置是否到達一個閥值決定是否對狀態列“蓋上紗布”,你可以通過setStatusBarScrim(Drawable)來設定紗布圖片,但是隻能在LOLLIPOP裝置上面有作用。預設statusBarScrim是colorPrimaryDark的色值.

(4)視差滾動子View(Parallax scrolling children): 子View可以選擇在當前的佈局當時是否以“視差”的方式來跟隨滾動。(PS:其實就是讓這個View的滾動的速度比其他正常滾動的View速度稍微慢一點)。將佈局引數app:layout_collapseMode設為parallax

(5)將子View位置固定(Pinned position children):子View可以選擇是否在全域性空間上固定位置,這對於Toolbar來說非常有用,因為當佈局在移動時,可以將Toolbar固定位置而不受移動的影響。 將app:layout_collapseMode設為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"

我們來看下效果:

在這裡插入圖片描述
appbar_8.gif

嗯嗯, 摺疊模式不對, toolbar的頂部圖示沒了. 我們改下摺疊模式:

app:layout_collapseMode="pin"

再看效果:

在這裡插入圖片描述

appbar_9.gif

我們把scrollFlags屬性改下, 看下對比:

app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed"

在這裡插入圖片描述

appbar_10.gif

效果還是蠻不錯的, 有了點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>

來看下效果:

在這裡插入圖片描述

appbar_11.gif

嗯, 有了點意思, 但不美觀, 上部的toolbar和圖片不協調. toolbar應該有預設的背景屬性, 我們去掉它看看.

 <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" />

再看下效果:

在這裡插入圖片描述

appbar_12.gif

這次真的不錯哦, 已經和很多大公司的app相像了. 但是為什麼去掉toolbar的background就可以得到透明背景呢? 說句實話, 沒找到原因.
不過我們沒有給CollapsingToolbarLayout設定contentScrim屬性哦, 給它加個屬性看看.

<android.support.design.widget.CollapsingToolbarLayout
    ...
    app:contentScrim="?attr/colorPrimary"
    ...>

在這裡插入圖片描述

appbar_13.gif

嗯嗯, 好像還不如沒設定這個屬性好呢.
什麼時候需要contentScrim屬性呢?
因為這個佈局裡面給CollapsingToolbarLayout的layout_scrollFlags設定的是 “scroll|enterAlways|enterAlwaysCollapsed” , toolbar會全部消失的, 所以感覺不是很美觀. 如果將layout_scrollFlags屬性改為 “scroll|exitUntilCollapsed” , 效果會好點, 適合toolbar還是需要展示的場合.

在這裡插入圖片描述

appbar_14.gif

不管怎麼樣, 先去掉contentScrim屬性吧.
目前有很多APP比較喜歡採用沉浸式設計, 簡單點說就是將狀態列和導航欄都設定成透明或半透明的.
我們來把狀態列statusBar設定成透明. 在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:fitsSystemWindows="true"
                ... />
        </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>

最後來看下效果:

在這裡插入圖片描述

appbar_15.gif

其實還可以在CollapsingToolbarLayout裡設定statusBarScrim為透明色, 不過有點問題, 最頂部的toolbar沒有完全隱藏, 還留了一點尾巴.

在這裡插入圖片描述

image.png

難道就這個屬性就沒用嗎? 我們把layout_scrollFlags改成 “scroll|exitUntilCollapsed” 看看:

在這裡插入圖片描述

image.png

這個時候toolbar不用隱藏, 所以還是美美的.
AppbarLayout整個做成沉浸式之後, 狀態列的圖示可能會受到封面圖片顏色過淺的影響, 可以給其加一個漸變的不透明層.
漸變遮罩設定方法:
在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節點中, 可以通過android:shape來設定形狀, 預設是矩形.
        gradient節點中angle的值270是從上到下,0是從左到右,90是從下到上。 
        此處的效果就是從下向上, 顏色逐漸由純透明慢慢變成黑透色-->
</shape>

佈局中, 在ImageView下面增加一個View, 背景設為上面的漸變遮罩.

<View
    android:layout_width="match_parent"
    android:layout_height="40dp"
    android:background="@drawable/status_gradient"
    app:layout_collapseMode="pin"
    android:fitsSystemWindows="true" />

給遮罩設定摺疊模式: app:layout_collapseMode=“pin” , 摺疊到頂部後定住. 來看下效果.

在這裡插入圖片描述

image.png

在這裡插入圖片描述

image.png

上圖是展開狀態的對比, 後面的是沒有新增遮罩的效果, 前面是添加了遮罩的效果. 下圖是添加了遮罩摺疊後的效果. 有點黑暗系影片的感覺哦.
FloatingActionButton再次表演
作為Google Material Design的一個重要控制元件, FloatingActionButton怎麼可能不在AppbarLayout中起點作用呢. 我們在佈局中加一個懸浮按鈕, 讓它的錨點掛載Appbar的右下角. 這樣這個懸浮按鈕就和Appbar關聯起來了.

<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>

我們來看下效果.

在這裡插入圖片描述

appbar_16.gif

好吧, 美美的Toolbar完成了, 有點Google Material Design撲面而來的感覺了.

作者:朋朋彭哥
連結:https://www.jianshu.com/p/bbc703a0015e