Material Design Patterns 教學 (5) - AppBarLayout
上次用過 CoordinatorLayout
控制 FAB 在 Snackbar
出現時移動,今次我們玩 AppBar
。
AppBar
最初叫 ActionBar
,後來改名為 Toolbar
,現在統稱叫 AppBar
。AppBarLayout
即是控制內容元件滑動時 AppBar
的顯示,需要在 CoordinatorLayout
底下才能運作。
AppBarLayout
簡單的用 CoordinatorLayout
再加上 AppBarLayout
包着 Toolbar
:
<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" />
</android.support.design.widget.AppBarLayout>
然後在 RecyclerView
加上 app:layout_behavior="@string/appbar_scrolling_view_behavior"
,並在 Toolbar
加上 app:layout_scrollFlags="scroll|enterAlways"
。這樣 CoordinatorLayout
便會在 RecyclerView
捲動時,去找自己當中受影響的 view
,在這裏即是 AppBarLayout
,作用相關的反應。
整個 layout 如下:
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="com.thirtysparks.tutorial.designlib.AnotherFabActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
/>
<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:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:layout_scrollFlags="scroll|enterAlways"
/>
</android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>
這樣便可輕易做到滑動 RecyclerView
時,自動顯示和隱藏 ToolBar
。
隱藏選項
在 AppBarLayout
加上的 app:layout_scrollFlags
可以是:
-
enterAlways
: scrolling view 任何向下的滑動,都會令AppBarLayout
重新顯示,就像上面的例子。 -
enterAlwaysCollapsed
: 要RecyclerView
回到最頂才顯示
exitUntilCollapsed
:RecyclerView
向上滑動時,AppBarLayout
會隱藏到minHeight
的高度,當向下滑動到最頂時才再顯示全部。
snap
(v23.1): 當RecyclerView
滑動到將view
顯示 75% 而停止時,會自動顯示整個view
。不會再有一半隱藏一半顯示的情況。如app:layout_scrollFlags="scroll|snap|exitUntilCollapsed"
的話,便有此效果:
CollapsingToolbarLayout
Support Design Library 還提供 CollapsingToolbarLayout
,它只可是 AppBarLayout
中唯一的 child ,而它的 child view 可加上 layout_collapseMode
去決定 CollapsingToolBarLayout
被隱藏時他們自身的顯示情況。最常見的用法是在滑動時將一個大圖和文字的 AppBar
縮為純文字。
layout_collapseMode
可以是 pin
或 parallax
,分別是在 CollapsingToolbarLayout
隱藏時會維持原狀和以 parallax
動畫隱藏。
好,來點例子說明。
用 CollapsingToolbarLayout
包著 ToolBar
,放進 AppBarLayout
中。然後將 ImageView
和 Toolbar
的 app:layout_collapseMode
分別設為 parallax
和 pin
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
>
<android.support.design.widget.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|snap|exitUntilCollapsed"
app:contentScrim="#ff4444"
app:expandedTitleMarginStart="4dp"
app:expandedTitleMarginEnd="8dp"
>
<ImageView
android:layout_width="match_parent"
android:layout_height="240dp"
android:src="@drawable/cat"
android:scaleType="centerCrop"
android:fitsSystemWindows="true"
app:layout_collapseMode="parallax"
/>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
便可以做到此效果。
Floating Action Button
用之前的方法加進 FAB,同時加進 layout_anchor
指向 AppBarLayout
<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_add_circle_outline_white"
android:elevation="6dp"
app:layout_anchor="@id/appbar_layout"
app:layout_anchorGravity="bottom|right|end"
app:pressedTranslationZ="12dp" />
這樣 AppBarLayout
隱藏的同時,FAB 也會跟著消失。簡單方便。
不過有一個問題,就是用 layout_anchor
的話,FAB 的位置會跟著 layout_anchor
的 layout
去擺放,所以以上例子中的 FAB 會永遠在 AppBarLayout
附近,而不能將它移到螢幕的底部。
要將它移回底部,只能放棄使用 layout_anchor
,改回使用 CoordinatorLayout.Behavior
(大家還記得在 Part 3 時用過吧?)。
public class ScrollingFabBehavior extends CoordinatorLayout.Behavior<FloatingActionButton> {
private int toolbarHeight;
public ScrollingFabBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
this.toolbarHeight = Utils.getToolbarHeight(context);
}
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, FloatingActionButton fab, View dependency) {
return dependency instanceof AppBarLayout;
}
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionButton fab, View dependency) {
if (dependency instanceof AppBarLayout) {
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) fab.getLayoutParams();
int fabBottomMargin = lp.bottomMargin;
int distanceToScroll = fab.getHeight() + fabBottomMargin;
float ratio = (float)dependency.getY()/(float)toolbarHeight;
fab.setTranslationY(-distanceToScroll * ratio);
}
return true;
}
}
(註:Copied 自 Michał Z)
結語
以前要使用 OnScrollListener
去設定 Toolbar
的顯示,現在透過 CoordinatorLayout
加上 AppBarLayout
便可簡單做到,非常方便。快為你的 app 加上此漂亮效果吧。
https://github.com/goofyz/android-material-design-tutorial/tree/part5_appbarlayout