AndroidのDrawerlayoutのtoolbarやDrawerButtonを(今更ながら)カスタマイズした話

こんにちは。medibaのauスマートパス開発部の小川です。

最近業務でAndroidアプリ開発を行っておりまして、(今更ですが)Drawerlayoutを加工する機会がありました。 その際に、簡単に出来そうなのに実装してみると悩んだ箇所をまとめてみようとか思います。

ちなみにNavigationViewを使ってはいるのですが主にtoolbarとDrawerlayoutへのカスタマイズの話になりますので、マテリアルデザインの話は出てきません。 NavigationViewは2015/5にAndroid Design Support Libraryに追加された機能で、これを使う事と今まで自分でRelativeLayoutをListViewにaddHeaderViewしていた実装を手軽に書く事が出来て便利なのですが、今回はそれより前段の話になります。

今回出てくるお話

概要

before

after

変更箇所

  1. toolbarの位置を上から下に変更(色も変更)
  2. DrawerButtonを変更
  3. Drawerが閉じた時に開くボタン(ドロイド君アイコン)を表示

コードについて

Android Studio(v1.5.1)のNavigation Drawew Activityの自動生成ファイルに対し、修正を行った箇所のみを記載しています。 メインコンテンツのWebViewの挿入はbefore,afterともにonCreate内で実施しています。

詳細

1.toolbarの位置を上から下に変更

デザインとしてはAndroidアプリっぽさが薄れますが、要件によっては下に持って行く必要に迫られる時もあります(した)。

app_bar_main.xmlのtoolbar周りの箇所

    <!-- MainActivity用のlayout-->
        <android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:theme="@style/AppTheme.AppBarOverlay">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical">

                <FrameLayout
                    android:layout_width="match_parent"
                    android:layout_height="match_parent">
                    <WebView
                        android:id="@+id/myWebView"
                        android:layout_width="match_parent"
                        android:layout_height="524dp"/>

                    <android.support.design.widget.FloatingActionButton
                        android:id="@+id/fab"
                        android:layout_width="wrap_content"
                        android:layout_height="68dp"
                        android:src="@android:drawable/ic_dialog_info"
                        android:layout_above="@+id/custom_toolbar"
                        android:layout_alignParentLeft="true"
                        android:layout_alignParentStart="true"
                        android:layout_gravity="left|bottom"/>
                </FrameLayout>
                <android.support.v7.widget.Toolbar
                    android:id="@+id/custom_toolbar"
                    android:background="@android:color/darker_gray"
                    xmlns:android="http://schemas.android.com/apk/res/android"
                    android:orientation="horizontal"
                    android:layout_alignParentBottom="true"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    app:popupTheme="@style/AppTheme.PopupOverlay"
                    android:layout_alignParentLeft="true"
                    android:layout_alignParentStart="true">
                </android.support.v7.widget.Toolbar>
            </LinearLayout>
        </android.support.design.widget.AppBarLayout>

こちら、xmlにてLinearLayoutで上下2段に区切ったのち、上段をFrameLayoutで括ったWebViewとFloatingActionButton、下段をToolbarとする事で Toolberを下部に移動させています。 Toolbarは他のViewと同様に扱う事が可能です。

2.DrawerButtonを変更

デザインとしてはAndroidアプリっぽさが薄れますが、要件によっては左上の「開く」ボタン(3本線アイコン)を配置場所、デザインともに変更する必要があります(した)。

今回はDrawerボタンを3本線アイコンからFloatingActionButton(画面左下に浮いている丸いボタン)に変更してみました。

MainActivity.javaのonCreateメソッド内にて

    // FloatingActionButtonを新たに追加
    fab = (FloatingActionButton) findViewById(R.id.fab);
    fab.setOnClickListener(new View.OnClickListener() {
        // クリック時の挙動を追加
        @Override
        public void onClick(View view) {
            // 追加したいImageViewを生成
            iv = new ImageView(MainActivity.this);
            iv.setImageResource(R.mipmap.ic_launcher);

            // 追加したImageViewの位置を指定
            iv.setScaleType(ImageView.ScaleType.FIT_END);
            FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(android.widget.FrameLayout.LayoutParams.WRAP_CONTENT,
            android.widget.FrameLayout.LayoutParams.WRAP_CONTENT);
            lp.topMargin = 1200;
            lp.leftMargin = 850;

            addContentView(iv, lp);

            // 初期は非表示に変更
            iv.setVisibility(View.GONE);

            DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
            // クリック時のイベントにドロワーメニューの開閉を追加
            if (drawer.isDrawerOpen(GravityCompat.START)) {
                // ドロワーメニューが開いた際に閉じる画像を非表示にする
                iv.setVisibility(View.GONE);
                drawer.closeDrawer(GravityCompat.START);
            } else {
                drawer.openDrawer(GravityCompat.START);
                // ドロワーメニューが開いた際に閉じる画像を表示する
                iv.setVisibility(View.VISIBLE);
            }
        }
    });

    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
    ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
            this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close) {

        @Override
        public void onDrawerClosed(View drawerView) {
            iv.setVisibility(View.GONE);
        }

        @Override
        public void onDrawerOpened(View drawerView) {
            iv.setVisibility(View.VISIBLE);
        }
    };
    drawer.setDrawerListener(toggle);
    toggle.syncState();

    NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
    navigationView.setNavigationItemSelectedListener(this);

    // ドロワー開くボタン(三本線)を非表示
    toggle.setDrawerIndicatorEnabled(false);

簡単に解説をしますと、 FloatingActionButtonに対しsetOnClickListenerを設定します。 そしてそこでOverrideするonCkickにてDrawerのOPEN,CLOSEを実行するようにします。

また下部でActionBarDrawerToggleとDrawerを紐付けているのはDrawerの状態を取得するonDrawerClosed,onDrawerOpenedを取得したかったためです。 表示上は不要なのでsetDrawerIndicatorEnabledにて3本線アイコンを非表示にします。

3.Drawerが閉じた時に開くボタンを表示

Drawerが画面を覆った際は、グレーアウトした画面右側の覆われていない箇所をタップするとDrawerが再度閉じます。 Drawer自体は既に多くのアプリに取り入れられていますので、UIとしてはかなりメジャーになっていますが 要件によっては明示的に閉じるボタンを表示させる必要があります(した)。

今回はドロイド君アイコンを、Drawarが閉じた際のみDrawarと同じ明るさでグレーアウト箇所右下に表示させています。

コードは↑のMainActivity.javaと共通していますのでそちらをご参照ください。 ここは何でつまづいたか言いますと、まず閉じるボタンをどこに定義するのが良いのかがわかりませんでした。。

予めlayoutファイルに記載しておくと、Drawerが開のいたタイミングでグレーアウトの中に入ってしまします。 かといってDrawerの中に入れると閉じるボタンの意味が半減してしまいます。 下のレイヤーはグレーアウトしつつ、欲しい画像のみ一番上のレイヤーに明るく表示する事が必要でした。

ということで、ここではonClick時に閉じるボタン用のViewを作成しています。 また、Drawerの状態変化に応じて

  • (開→閉)の時→ボタンを表示
  • (閉→開)の時→ボタンを非表示

と切り替えています。 もう少し細かくDrawerの挙動ステータスを管理すれば、Drawerが動き始めた瞬間に表示を切り替える事も可能です。

感想

今更ながらのDrawerlayoutなのですが細かい部分は都度試行錯誤になりますので、今回に関してももっと綺麗に出来る部分があるのではないかと思います。 基本的にはGoogleが推奨しているデザインを踏襲しながらサービス独自のデザインを実現するためには、何が簡単に出来て何が難しいのかを判断をできる様にしておく事が大切だと今更ながらに思います。