Navigation Drawerだけを持つ背景が透過したActivityを作成した時にハマった事


背景

アプリの仕様上の問題で、Navigation Drawerを出すときに、Navigation Drawerだけを持つ背景が透過しているActivityをメニューを出す画面の上に重ねて表示することで実現することになった。
その時にハマった事及びそれを解決する過程で学んだことがあった。

領域外タッチでdrawerが閉じない!

最初、Navigation Drawerだけを置いたactivityのレイアウトは以下のようにしてた。

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <androidx.drawerlayout.widget.DrawerLayout
        android:id="@+id/drawer"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:fitsSystemWindows="true">

        <com.google.android.material.navigation.NavigationView
            android:id="@+id/navigation"
            android:layout_width="wrap_content"
            android:layout_height="fill_parent"
            android:layout_gravity="left"
            android:background="#ffffff"
            android:fitsSystemWindows="false"
            app:headerLayout="@layout/navigation_header" />


    </androidx.drawerlayout.widget.DrawerLayout>
</layout>

しかしこうすると、表示はされるしNavigation Drawerを左にスライドをすれば閉じることはできるものの、Navigation Drawer以外の領域をタッチしても閉じなくなってしまいました。

解決法

そこで以下のように、DrawerLayoutの直下に透明なViewを置いてやったところ、領域外をタッチして閉じるようになりました。

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <androidx.drawerlayout.widget.DrawerLayout
        android:id="@+id/drawer"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:fitsSystemWindows="true">

     <!--ハンバーガーメニュー外の領域をタッチした時に閉じるようにするようにするための透明なView-->
        <View
            android:id="@+id/view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#00000000" />

        <com.google.android.material.navigation.NavigationView
            android:id="@+id/navigation"
            android:layout_width="wrap_content"
            android:layout_height="fill_parent"
            android:layout_gravity="left"
            android:background="#ffffff"
            android:fitsSystemWindows="false"
            app:headerLayout="@layout/navigation_header" />


    </androidx.drawerlayout.widget.DrawerLayout>
</layout>

どうやらDrawerLayoutはメインコンテンツがないとNavigationViewの領域外へのタッチでハンバーガーメニューが閉じるようにならないらしい。
(というより直下のViewをメインコンテンツと認識する?)

上記を解決する過程で発見したこと - Navigation Drawerの背景色の変え方

ところで、元々DrawerLayout+NavigationViewだけの時はNavigation Drawerの領域外の部分の背景色がActivityの色になっていたため、自前でActivityの背景を黒の半透明色にしていた。
だが、透明なViewを追加したところActivityの背景色を透明にしていてもNavigation Drawer外の部分の背景色が勝手によく見る黒の半透明になった。

なぜだろう…?とDrawerLayoutの公式ドキュメントを見たところsetScrimColor(int color)という背景色をセットするメソッドを発見した。
https://developer.android.com/reference/android/support/v4/widget/DrawerLayout.html#setscrimcolor
そこでsetScrimColorメソッドの実装を確認すると


  /**
     * Set a color to use for the scrim that obscures primary content while a drawer is open.
     *
     * @param color Color to use in 0xAARRGGBB format.
     */
    public void setScrimColor(@ColorInt int color) {
        mScrimColor = color;
        invalidate();
    }

そして、このメソッドで値をセットされる変数mScrimColorは、子Viewを描写するときにNavigation Drawer外の部分を描写する際に

 @Override
    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
        ()

        if (mScrimOpacity > 0 && drawingContent) {
            final int baseAlpha = (mScrimColor & 0xff000000) >>> 24;
            final int imag = (int) (baseAlpha * mScrimOpacity);
            final int color = imag << 24 | (mScrimColor & 0xffffff);
            mScrimPaint.setColor(color);

            canvas.drawRect(clipLeft, 0, clipRight, getHeight(), mScrimPaint);
        }

       (以下略)
    }

という風に使われている。
また、setScrimColorで値をセットしている変数mScrimColorの初期値は

 private static final int DEFAULT_SCRIM_COLOR = 0x99000000;

 (中略)

 private int mScrimColor = DEFAULT_SCRIM_COLOR;

である。

つまりメインコンテンツを足したことでNavigation Drawerの背景にあたる部分がちゃんと描写されるようになり、変数mScrimColorの値が反映されるようになり、今回は明示的に背景色をセットしなかったので初期値の0x99000000になったらしい。
そして、Navigation Drawerの背景色を例えばピンクなど、アプリのデザインにあったカラーにカスタマイズしたいときはsetScrimColorメソッドを呼べばいいらしい。なるほど。