How to specify a fully transparent SystemBar (NavigationBar + StatusBar) in Android (API level >= 30)

公開日: 2022年01月27日最終更新日: 2022年01月28日

transparent-system-bar.png

SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION is deprecated at API level 30, and it is recommended to use (setDecorFitsSystemWindows)[https://developer.android.com/reference/android/view/Window#]

Setting up a theme

Specify the colors of StatusBar and NavigationBar to be transparent in the theme.
Note that the SystemBar will not be transparent if android:windowDrawsSystemBarBackgrounds is set to false.
In Material themes, android:windowDrawsSystemBarBackgrounds is true, so you don't need to specify it, but you can specify it in your theme if necessary.

<resources>
    <!-- Base application theme. -->
    <style name="Theme.TransparentSystemBarStudy" parent="Theme.MaterialComponents.DayNight.NoActionBar">
        ...
        <item name="android:statusBarColor">@android:color/transparent</item>
        <item name="android:navigationBarColor">@android:color/transparent</item>
    </style>
</resources>

The same is true if you do the following in your code.

window.setStatusBarColor(Color.TRANSPARENT);
window.setNavigationBarColor(Color.TRANSPARENT);

Add the following to the application tag in AndroidManifest.xml and apply the theme you created.

  <application
        ...
        android:theme="@style/Theme.TransparentSystemBarStudy">

Setting up onCreate

Next, extend the drawing area of the application to the back of the SystemBar. Set setDecorFitsSystemWindows to false. Then the app's drawing area will be the entire screen.

setStatusBarContrastEnforced and setNavigationBarContrastEnforced to false so that scrim is not displayed in the background even if there is insufficient contrast between the icon and the background.

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContentView(R.layout.activity_main)

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            window.setDecorFitsSystemWindows(false)
            window.setStatusBarContrastEnforced(false)
            window.setNavigationBarContrastEnforced(false)
        }
    }

I haven't fully checked the processing here, but without this, I think Scrim is displayed even if the contrast with the background is sufficient, and the NavigationBar is not completely transparent.
The StatusBar is transparent, but I'm also a little concerned about the fact that in the case of 3-button navigation, Scrim is displayed unless it is called after setContentView. (I'll look into this later if I have time...)

The scrim of the NavigationBar is a black translucent background as shown in the image below.

scrim-navigation-bar

Layout settings

Since the drawing area extends to the back of the SystemBar, if we lay out the GUI as it is, the GUI will go behind the StatusBar and NavigationBar. Therefore, by specifying android:fitsSystemWindows="true" to LayoutGroup, you can place the GUI in an area that avoids the SystemBar.

If you include this, the GUI will be laid out in an area that avoids the SystemBar area. In the following example, the ImageView is displayed in the entire area, and the TextView is placed inside the SystemBar.

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:contentDescription="image"
        android:scaleType="centerCrop"
        android:src="@drawable/image" />

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true">

        <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#8888FF88"
            android:text="Hello World!"
            android:textSize="64sp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#888888FF"
            android:text="Hello World!"
            android:textSize="64sp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>

Reference