スクロール連動用画面部品
それでは、ここで使用した各画面部品、つまりタグと属性を解説していきます。
CoordinatorLayout
coordinatorという英単語は、調整役という意味です。CoordinatorLayoutはその名の通り、画面部品同士の動きを調整するレイアウトです。今回はテキスト部分のスクロールに連動してアクションバーが隠れたり出てきたりするような処理ですが、このように親子関係のない画面部品同士に連動した動きをさせる場合は、まず全体をCoordinatorLayoutで囲む必要があります。
なお、CoordinatorLayoutはFrameLayoutと同じような機能を持っています(FrameLayoutを継承しているわけではありません)。したがって、使い方によっては以下のように画面部品同士が重なってしまうので注意が必要です。
AppBarLayout
ところで、どのようにして図5のようになったのでしょうか。実はこれ、リスト1から<AppBarLayout>タグを削除した状態です。図5の状態では、テキスト部分をスクロールしてもアクションバー部分が連動しません。アクションバー部分を連動させるための画面部品がこのAppBarLayoutです。
AppBarLayoutは、縦並びのLinearLayoutです(こちらは実際にLinearLayoutを継承しています)。そのため、AppBarLayout内の画面部品は縦に並べられ、それらがアクションバーの位置に配置されます。そして、このAppBarLayout内の画面部品にapp:layout_scrollFlags属性を記述することで、スクロールが連動する仕組みです。それがリスト1の(5)です。記述方法ですが、まず「scroll」と記述します。その後、「|」で区切りをつけ、以下のスクロールモードのどれかを指定します。
- enterAlways:上にスクロールすると、AppBarLayout部分がすぐに消えて、下にスクロールするとすぐにAppBarLayout部分が出てきます。
- enterAlwaysCollapsed:上にスクロールすると、AppBarLayout部分がすぐに消えますが、下にスクロールした場合はスクロールの上端まで行ったときにようやくAppBarLayout部分が出てきます。
- exitUntilCollapsed:スクロールによるAppBarLayoutの見え隠れはenterAlwaysCollapsedと同じですが、AppBarLayoutの一部が画面内に残ります。
リスト1では「scroll|enterAlways」を指定していますが、ここでは、このenterAlways以外の値を指定してもちゃんと動作しません。これに関しては次節で扱います
なお、このapp:属性を指定するためには、あらかじめapp:名前空間を読み込んでおく必要があります。それがリスト1の(2)です。
ところで、先述のようにAppBarLayoutを使用すると、AppBarLayoutがアクションバーの位置を陣取ります。そのため、影を付けるandroid:elevation属性に関して、前回のようにToolbarに設定しても機能しません。そこで、ここでは、AppBarLayoutに移動してあります。それがリスト1の(4)です。
NestedScrollView
前回のサンプルでは、TextViewをスクロールさせるためにScrollViewを使用しました。今回のサンプルで、前回同様にリスト1の(6)の位置にScrollViewを使用しても、スクロール連動にはなりません。それは、ScrollViewがCoordinatorLayoutと連携する機能を持っていないからです。CoordinatorLayoutと連携するためには、NestedScrollingChildインターフェースを実装したものでなければなりません。それが、NestedScrollViewなのです。
さらに、NestedScrollViewを使っただけでは連動しません。このタグに
app:layout_behavior="@string/appbar_scrolling_view_behavior"
属性を記述しておく必要があります。これは、このまま記述してください。
なお、ここでは、@stringとstrings.xmlの記述を指定するようになっていますが、strings.xmlにname属性がappbar_scrolling_view_behaviorのタグをこちらで用意する必要はありません。これは、リスト1の(2)で読み込んだ名前空間に含まれています。
まとめ
少しややこしくなってきているため、ここでまとめておきましょう。enterAlwaysモードでスクロール連動させたい場合は、
<CoordinatorLayout>
<AppBarLayout>
<Toolbar />
</AppBarLayout>
<NestedScrollView>
…
</NestedScrollView>
</CoordinatorLayout>
の形で使用します。そのうえで、
- <toolbar>に「app:layout_scrollFlags="scroll|enterAlways"」を記述
- <nestedscrollview>に「app:layout_behavior="@string/appbar_scrolling_view_behavior"」を記述
とします。
CollapsingToolbarLayout
では、enterAlwaysCollapsedモードやexitUntilCollapsedで連動させたい場合はどのようにすればいいのでしょうか。それは、もうひとつCollapsingToolbarLayoutというレイアウト部品を導入する必要があります。
activity_scroll_article.xmlの<AppBarLayout>内の記述を以下のように改造してください。
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="180dp" // (1)
android:elevation="10dp">
<android.support.design.widget.CollapsingToolbarLayout // (2)
android:id="@+id/toolbarLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
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" // (3)
android:background="@color/colorPrimary"/>
</android.support.design.widget.CollapsingToolbarLayout> // (2)
変更点は以下の3点です。
- (1) AppBarLayoutのlayout_heightの値
- (2) CollapsingToolbarLayoutタグの追加
- (3) layout_scrollFlagsを削除し、代わりにlayout_collapseModeを追加
この時点で一度アプリを再起動してみてください。以下のような画面になっています。
スクロールすると、スクロールに連動してアクションバーが小さくなり、以下のような画面になります。
ここで導入したCollapsingToolbarLayoutというのは、スクロール時にそれに連動させてAppBarLayoutのサイズを変更するレイアウト部品です。サイズを変更するために、まずAppBarLayoutの高さを固定値180dpとしています。それが(1)の変更です。この高さが初期状態となります。
その後、スクロールに応じてサイズが縮小しながら最小状態まで変化するように設定します。これは、CollapsingToolbarLayoutの役割なので、いままでToolbarに設定していたlayout_scrollFlagsをCollapsingToolbarLayoutに移動し、スクロールモードをexitUntilCollapsedとしています。
では、どこまで縮小するのかというと、アクションバーの本来の高さまでです。そのためには、Toolbarにはアクションバーの位置にとどまってもらう必要があります。それを指定する属性が(3)のlayout_collapseModeです。この属性値を「pin」とすることで、Toolbarは常にアクションバーの位置にとどまります。
ところで、実行した画面をよく見ると、図5では白色だったタイトル「Material!」文字色はここでは黒に戻っています。また、サブタイトルも消えています。これらは、Toolbarに設定したものですが、CollapsingToolbarLayoutを利用すると、Toolbarよりもこちらが優先されてしまうので、Toolbarへの設定が反映されません。そこで、ScrollArticleActivityのonCreate()メソッドを改造しましょう。super.onCreate()とsetContentView()以外を以下のように記述してください。
protected void onCreate(Bundle savedInstanceState) {
~省略~
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setLogo(R.mipmap.ic_launcher); // (1)
setSupportActionBar(toolbar);
CollapsingToolbarLayout toolbarLayout = (CollapsingToolbarLayout) findViewById(R.id.toolbarLayout);
toolbarLayout.setTitle(getString(R.string.toolbar_title)); // (2)
toolbarLayout.setExpandedTitleColor(Color.WHITE); // (3)
toolbarLayout.setCollapsedTitleTextColor(Color.LTGRAY); // (4)
}
Toolbarへの設定をロゴのみとして(リスト3の(1))、代わりにタイトルの設定をCollapsingToolbarLayoutに対して行っています(リスト3の(2))。ただし、CollapsingToolbarLayoutのsetTitle()メソッドはR値での指定ができません。getString()メソッドを使って、R値を文字列に変換しています。
また、CollapsingToolbarLayoutはサブタイトルの設定メソッドはないので、サブタイトルは使用していません。代わりに、通常サイズ時と縮小サイズ時のタイトル文字色を別々に設定できます。それを行っているのが、(3)と(4)です。前者がsetExpandedTitleColor()メソッドで、後者がsetCollapsedTitleTextColor()メソッドです。色指定の方法はToolbarと同じです。
この状態で一度アプリを再起動してください。タイトル文字色が通常サイズの場合は白色で、スクロールすると薄いグレーに変化するのが確認できると思います。
