画面をスクロールした際にヘッダーを隠すような挙動をCoordinatorLayout
で実装できます。
最近、とあるアプリの画面にこの挙動を実装した際にいろいろ試行錯誤したので、「こうやったらヘッダーがうまく隠れてくれたぜイェーイ」ってなった例や、「ここでこうやったらレイアウトも崩れなかったぜイェーイ」ってなったテンションのままで書いてます。
ヘッダーを隠すために
スクロールしたらヘッダーを隠せるようにするUIを作るための基礎知識とかです。
とりあえずこの内容が把握出来てると、あれこれしてるうちになんとなくできる。
スクロールするレイアウト
CoordinatorLayout
でスクロール時にヘッダーを隠す挙動を行いたい際は、スクロールする部分がNestedScrollView
かRecyclerView
である必要があります。
ここをScrollView
とかListView
の状態で「ヘッダーが・・・隠れない・・・!」ってなった人もいるかもしれないですね。
とりあえずCoordinatorLayout
のリファレンスを見に行ってもこの辺りは記載されておらず、AppBarLayout
の方に書かれているので、初めてする人だと引っかかる人もいるかもしれません。
あと、「ひとまずこのレイアウトをスクロールしたらヘッダーを隠したいぜ」という場合ですが、そのときは「スクロールしたいレイアウト」を子にもっている、「隠したいヘッダーを子レイアウトに持つCoordinatorLayout
」の子レイアウトにつけておきましょう。 自分で書いておいてあれだけどめっちゃわかりにくいな・・・。
隠すヘッダー
隠したいヘッダー部分は、AppBarLayout
の要素内に配置する必要があります。
あと、このAppBarLayout
はCoordinatorLayout
の直下になければいけません。
AppBarLayout
内にヘッダーを配置し、次のようにapp:layout_scrollFlags
属性を設定すると、設定した値に従ってスクロール時にAppBarLayout
が隠れてくれるナイスなレイアウトになってくれます。
<AppBarLayout ...>
<ToolBar ...
app:layout_scrollFlags="scroll|enterAlways"
/>
</AppBarLayout>
上のサンプルだと、下方向にスクロールするとAppBarLayoutが隠れて、上方向にスクロールすることでAppBarLayoutが表示されるようになります。
layout_scrollFlags
に指定できるフラグについてはこちらをどうぞ。
基本を抑えたうえで
スクロール時にヘッダーを隠すレイアウトを作成するための基礎知識はこんなところです。
ただ、スクロールするレイアウトの階層が深いところにあったり、別のレイアウトファイルをincludeしていたり、フラグメントであった場合にちゃんと隠れてくれるのか?というところは一度試してみないとわからないところです。
次の画像のようなレイアウトで、Toolbarを隠すようなアプリを目標にして、
そういった場合についていくつか試してみたので、参考例として一覧をあげていきます。
成功例
スクロールするレイアウトxmlがヘッダーのあるレイアウトxmlと別のとき
// TODO それっぽいレイアウト(隠すヘッダーを示す)
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
...
app:layout_scrollFlags="scroll|enterAlways"/>
</android.support.design.widget.AppBarLayout>
<include layout="@layout/view_pager" />
</android.support.design.widget.CoordinatorLayout>
</LinearLayout>
<android.support.v4.widget.NestedScrollView
android:id="@+id/pager"
android:layout_below="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<!-- 中略 -->
</android.support.v4.widget.NestedScrollView>
AppBarLayoutにスクロール時に隠したいものと隠したくないものを含みたい
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
...
app:layout_scrollFlags="scroll|enterAlways"/>
<android.support.design.widget.TabLayout
android:id="@+id/tab"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</android.support.design.widget.TabLayout>
</android.support.design.widget.AppBarLayout>
<include layout="@layout/view_pager"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</android.support.design.widget.CoordinatorLayout>
</LinearLayout>
<android.support.v4.view.ViewPager
android:id="@+id/pager"
android:layout_below="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</android.support.v4.view.ViewPager>
失敗例
AppBarLayoutが「1. 隠したくないもの、2. 隠したいもの」で構成されてる
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
.../>
<android.support.design.widget.TabLayout
android:id="@+id/tab"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|enterAlways">
</android.support.design.widget.TabLayout>
</android.support.design.widget.AppBarLayout>
<include layout="@layout/view_pager" />
</android.support.design.widget.CoordinatorLayout>
</LinearLayout>
<android.support.v4.view.ViewPager
android:id="@+id/pager"
android:layout_below="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</android.support.v4.view.ViewPager>
上記のような例だと、スクロール時にヘッダーを隠す動作が実行されません。
この場合、AppBarLayout内の一番上にある隠したくないViewを、さらに上位の階層に移すことで解決するほかないと思います。
(※まあこんなUIになる場合に、一番上の隠したくないViewはそれ以下のLayoutとは別の責務を持つことが多いと思うので同じレイアウトファイルに収まってるのがおかしいのかな、とも思います)
しめ
という感じで成功例ふたつ失敗例ひとつという感じで紹介しました。
この先すすめていくとBehaviorを自作する話になってくるのですが、これは後日で。