マテリアルなナビゲーションドロワー。
今のGoogle製のアプリはおおよそこういう見た目になっています。
記事の端末は若干古く、記事のコメントにあるSSのようにステータスバー領域までナビゲーションドロワーが被ってくるようなのがマテリアルなやつらしいです。
で、これどう作るんでしょうね。
NavigationDrawerテンプレート
- Android Studio 1.0.2
- Android SDK Tools 24.0.2
- Android SDK Platform-tools 21
NavigationDrawer
テンプレートでプロジェクトを作ってもこういう動きにはなりません。それどころか、ハンバーガーボタンが動かなくて違和感が酷いです。(自分の環境が最新になってないだけだったらすみません)
これはandroid.support.v4.app.ActionBarDrawerToggle
が廃止され、android.support.v7.app.ActionBarDrawerToggle
へ移行したのが原因です。
ドキュメントがまだ整備されていなくて、Creating a Navigation Drawer | Android Developersの記述も古いままなんですよね…。
ic_drawer.png
をゴミ箱に投げ捨てて、インポートするActionBarDrawerToggle
をv4
からv7
に変えましょう。
//android.support.v7.ActionBarDrawerToggle mDrawerToggle = new ActionBarDrawerToggle(getActivity(), mDrawerLayout, R.string.navigation_drawer_open, R.string.navigation_drawer_close)
ただこれも過渡期の、ハンバーガーボタンが矢印にアニメーションするやつで、今風ではないのです。
ActionBarの上にドロワーを載せるには?
どう頑張っても無理だと思うんです。ビュー階層がそもそも違うので。
アプリケーションの最上層には、Window#getDecorView()
で取得できる、android:id/dector_content_parent
があって、android:id/action_bar_container
とandroid:id/content
(xmlで指定したレイアウト)はその子要素となっているはずなのです。
というわけで、適当にGmailアプリのビュー階層をダンプしてみました。
com.google.android.gm:id/action_bar_root
の下にandroid:id/content
があります。ドロワーはその子要素となっています。
ActionBar
っぽく見えてるのはさらにその下にあるcom.google.android.gm:id/mail_toolbar
というただのView
です。
これはサポートパッケージのActionBarActivity
を使った上で、
<item name="windowActionBar">false</item> <item name="android:windowNoTitle">true</item>
でActionBar
を消し去った上で、さらに代替としてToolbar
を使っているっ挙動っぽい。
ioschedの実装を読もう
マテリアルデザインのお手本とされているioschedを読んでみます。
前読んだときは、UI部分はスルーしてました。
src/main/res/values/styles.xml
より、
<style name="Theme.IOSched.Base" parent="Theme"> ...(省略) <item name="windowActionBar">false</item> <item name="android:windowNoTitle">true</item> ...(省略) </style> <style name="Theme.IOSched.WithNavDrawer" parent="Theme.IOSched" />
src/main/res/values-v21/styles.xml
より、
<style name="Theme.IOSched.WithNavDrawer" parent="Theme.IOSched"> <item name="android:statusBarColor">@android:color/transparent</item> </style>
アクションバー消してるのは予想通り。styles
で空のテーマを作っておいて、v21
だけステータスバーを透明にしてます。v21
なんですね。4.4のimmersive mode
(あまり知らない)だと思ってたので意外。
src/main/com/google.samples/apps/iosched/ui/BaseActivity.java
より、
// Primary toolbar and drawer toggle private Toolbar mActionBarToolbar; protected Toolbar getActionBarToolbar() { if (mActionBarToolbar == null) { mActionBarToolbar = (Toolbar) findViewById(R.id.toolbar_actionbar); if (mActionBarToolbar != null) { setSupportActionBar(mActionBarToolbar); } } return mActionBarToolbar; }
ですよねー。
setSupportActionBar()
ってもうこのために存在するメソッドとしか思えませんでしたし…。
setSupportActionBar()
というのは、引数に渡したandroid.support.v7.widget.Toolbar
をActionBarとして利用するメソッドです。
本物のActionBarをThemeで非表示にした上で、レイアウト上にあるToolbar
をActionBarとして利用することによって、画面全体にナビゲーションドロワーが表示されるようにしているのです。
private void goToNavDrawerItem(int item) { Intent intent; switch (item) { case NAVDRAWER_ITEM_MY_SCHEDULE: intent = new Intent(this, MyScheduleActivity.class); startActivity(intent); finish(); break; ...(以下略)
ドロワーからアイテム選択されたらstartActivity()
した後、自身をfinish()
してます。
つまり、ドロワーのルートになる全てのレイアウトがToolbar
とNavigationDrawer
のリスト部分をinclude
してるんですね。ドロワー内のリストの選択状態は各Activity
で管理なんでしょうか。
ドロワーが閉じてる最中にstartActivity()
したら見た目の整合性取れないよね?と思ったら、postDelayed()
でstartActivity()
にディレイを掛けて、ドロワーが閉じた後に移動するよう見せかけてます。
これ微妙すぎるのでは…。
ActionBarActivityを使わない場合
API Lv21以降はsetActionBar()
でsetSupportActionBar()
と同じことができます。
ただし、この引数のToolbar
はandroid.support.v7.widget.Toolbar
ではなく、 android.widget.Toolbar
です。両者は全く別物です…。