System Bar:表示・非表示の制御(≧Api30)

投稿日:  更新日:

アプリケーションの種類によってはSystem Barを非表示にしたい場合があります。

例えば、没入したいゲームはStatus Barを非表示にして、システムからの割り込みを無くすことが望ましいでしょう。

System Barはデフォルトでアプリに表示されますが、プログラムで非表示にすることも可能です。

System Barの表示・非表示の制御について紹介します。

スポンサーリンク

WindowInsetsControllerを使った制御

System barの表示・非表示の制御はWindowInsetsController#show( )/hide( )メソッドで行われます。

メソッドと引数に与えるパラメータは表の通りです。

メソッド引数A
WindowInsets.Type.*
System Bar
非表示
System Bar
表示
hide(A)statusBars()Status Bar非表示
navigationBars()Navigation Bar非表示
systemBars()System Bar非表示
show(A)statusBars()Status Bar表示
navigationBars()Navigation Bar表示
systemBars()System Bar表示
※色はメソッドと引数が影響を及ぼす動作を表します。

また、非表示になったSystem Barを再表示させる操作方法はwindowInsetsController#systemBarsBehaviorへ指定するフラグにより変更できます。

フラグの動作は表の通りです。

フラグ
BEHAVIOR_SHOW_*
System Bar
非表示
System Bar
再表示
BARS_BY_TOUCH
(デフォルト)
Status Barの非表示上端からスワイプで再表示
Navigation Barの非表示タッチで再表示
System Barの非表示
 (Status Bar)
 (Navigation Bar)

上端からスワイプで再表示(*1)
タッチで再表示
BARS_BY_SWIPEStatus Barの非表示上端からスワイプで再表示
Navigation Barの非表示下端からスワイプで再表示
System Barの非表示上下端からスワイプで再表示
TRANSIENT_BARS_BY_SWIPEStatus Barの非表示上端からスワイプで一定時間表示
※黒の半透明
Navigation Barの非表示下端からスワイプで一定時間表示
※黒の半透明
System Barの非表示上下端からスワイプで一定時間表示
※黒の半透明
*1:スワイプは先にタッチが発生するのでNavigation Barが表示されてしまう
※色はフラグが影響を及ぼす動作を表します。

ただし、WindowInsetsController#show( )/hide( )はApi30で追加になったメソッドです。<Api30で用いていたView#systemUiVisibilityの代替になります。

スポンサーリンク

System Barの表示・非表示

表示・非表示の実行例です。

非表示の様子は子Viewのレイアウト属性を参照してください。layout_marginとpaddingとgravityを使って実現されている事が分かります。

【参考】レイアウト属性をダンプするメソッド
    fun dumpViewStructure(view: View) {
        val _parent = view.parent
        if(_parent is ViewGroup) {
            Log.i(TAG, "Class = ${_parent.javaClass.simpleName}")
            _parent.forEachIndexed { index, view ->
                Log.i(TAG, "  Class = ${view.javaClass.simpleName}")
                val _XY = IntArray(2)
                view.getLocationInWindow(_XY)
                Log.i(TAG, "    Position = (${_XY[0]}, ${_XY[1]})")
                Log.i(TAG, "    Size     = ${view.width}x${view.height}")
                if(_parent is FrameLayout) {
                    val _params = view.layoutParams as FrameLayout.LayoutParams
                    // MATCH_PARENT -> -1, WRAP_CONTENT -> -2
                    Log.i(TAG, "    Layout Width, Height = %d,%d".format(
                            _params.width,
                            _params.height
                        ))
                    Log.i(TAG, "    Layout Margin LTRB   = %d,%d,%d,%d".format(
                            _params.leftMargin,
                            _params.topMargin,
                            _params.rightMargin,
                            _params.bottomMargin
                        ))
                    // BOTTOM -> 80, TOP -> 48
                    Log.i(TAG, "    Layout Gravity       = %d".format(
                            _params.gravity
                        ))
                }
                Log.i(TAG, "    Padding LTRB         = %d,%d,%d,%d".format(
                        view.paddingLeft,
                        view.paddingTop,
                        view.paddingRight,
                        view.paddingBottom
                    ))
                // VISIBLE   -> 0, INVISIBLE -> 4, GONE -> 8
                Log.i(TAG, "    Visibility           = %d".format(
                    view.visibility
                ))
            }
            dumpViewStructure(_parent)
        }
    }

WindowInsets.Type.statusBars()

Status Barを非表示にします。

非表示にされたStatus Barは上端からのスワイプで再表示できます(デフォルト動作)。

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        ...
        window.decorView.windowInsetsController?.apply {
            hide(WindowInsets.Type.statusBars())
        }
	    ...
	}
【hide(….statusBars())】

hide(WindowInsets.Type.statusBars())
※LTRB : Left,Top,Right,Bottom
【子Viewのレイアウト属性】

Class = DecorView
  Class = LinearLayout(Contents)
    Position = (0, 0)
    Size     = 320x432
    Layout Width, Height = -1,-1
    Layout Margin LTRB   = 0,0,0,48
    Layout Gravity       = -1
    Padding LTRB         = 0,0,0,0
    Visibility           = 0(Visible)
  Class = View(Navigation)
    Position = (0, 432)
    Size     = 320x48
    Layout Width, Height = -1,48
    Layout Margin LTRB   = 0,0,0,0
    Layout Gravity       = 80(Bottom)
    Padding LTRB         = 0,0,0,0
    Visibility           = 0(Visible)
  Class = View(Status)
    Position = (0, 0)
    Size     = 320x0
    Layout Width, Height = -1,0
    Layout Margin LTRB   = 0,0,0,0
    Layout Gravity       = 48(Top)
    Padding LTRB         = 0,0,0,0
    Visibility         = 4(Invisible)

WindowInsets.Type.navigationBars()

Navigation Barを非表示にします。

非表示にされたNavigation Barは画面のタッチで再表示できます(デフォルト動作)。

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        ...
        window.decorView.windowInsetsController?.apply {
            hide(WindowInsets.Type.navigationBars())
        }
	    ...
	}
【hide(….navigationBars())】

hide(....navigationBars())
※LTRB : Left,Top,Right,Bottom
【子Viewのレイアウト属性】

Class = DecorView
  Class = LinearLayout(Contents)
    Position = (0, 0)
    Size     = 320x480
    Layout Width, Height = -1,-1
    Layout Margin LTRB   = 0,0,0,0
    Layout Gravity       = -1
    Padding LTRB         = 0,24,0,0
    Visibility           = 0(Visible)
  Class = View(Navigation)
    Position = (0, 480)
    Size     = 320x0
    Layout Width, Height = -1,0
    Layout Margin LTRB   = 0,0,0,0
    Layout Gravity       = 80(Bottom)
    Padding LTRB         = 0,0,0,0
    Visibility         = 4(Invisible)
  Class = View(Status)
    Position = (0, 0)
    Size     = 320x24
    Layout Width, Height = -1,24
    Layout Margin LTRB   = 0,0,0,0
    Layout Gravity       = 48(Top)
    Padding LTRB         = 0,0,0,0
    Visibility           = 0(Visible)

WindowInsets.Type.systemBars()

System Barを非表示にします。

非表示にされたStatus Barは上端からのスワイプで、navigation Barは画面のタッチで再表示できます(デフォルト動作)。

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        ...
        window.decorView.windowInsetsController?.apply {
            hide(WindowInsets.Type.systemBars())
        }
	    ...
	}
【hide(….systemBars())】

hide(....systemBars())
※LTRB : Left,Top,Right,Bottom
【子Viewのレイアウト属性】

Class = DecorView
  Class = LinearLayout
    Position = (0, 0)
    Size     = 320x480
    Layout Width, Height = -1,-1
    Layout Margin LTRB   = 0,0,0,0
    Layout Gravity       = -1
    Padding LTRB         = 0,0,0,0
    Visibility           = 0(Visible)
  Class = View
    Position = (0, 480)
    Size     = 320x0
    Layout Width, Height = -1,0
    Layout Margin LTRB   = 0,0,0,0
    Layout Gravity       = 80(Bottom)
    Padding LTRB         = 0,0,0,0
    Visibility         = 4(Invisible)
  Class = View
    Position = (0, 0)
    Size     = 320x0
    Layout Width, Height = 1,0
    Layout Margin LTRB   = 0,0,0,0
    Layout Gravity       = 48(Top)
    Padding LTRB         = 0,0,0,0
    Visibility         = 4(Invisible)

非表示⇒表示の切り替え

System Barを「非表示⇒表示」に切り替えます。

メソッドwindowInsetsController#show()を使います。

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        ...
        window.decorView.windowInsetsController?.apply {
            // show(WindowInsets.Type.statusBars())
            // show(WindowInsets.Type.navigationBars())
            show(WindowInsets.Type.systemBars())
        }
	    ...
	}
スポンサーリンク

System Barの再表示

非表示にしたSystem Barは画面の操作で再表示できます。その操作方法がwindowInsetsController#systemBarsBehaviorに指定するフラグにより決まります。

再表示の実行例です。

BEHAVIOR_SHOW_BARS_BY_TOUCH

非表示にされたStatus Barは上端からのスワイプで、Navigation Barは画面のタッチで再表示されます。

デフォルトの動作です。フラグの指定が無い場合はこの動作になります。

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        ...
        window.decorView.windowInsetsController?.apply {
            hide(WindowInsets.Type.systemBars())
            systemBarsBehavior = BEHAVIOR_SHOW_BARS_BY_TOUCH
        }
	    ...
	}

BEHAVIOR_SHOW_BARS_BY_SWIPE

非表示にされたSystem Barは画面の上端または下端からのスワイプで再表示されます。

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        ...
        window.decorView.windowInsetsController?.apply {
            hide(WindowInsets.Type.systemBars())
            systemBarsBehavior = BEHAVIOR_SHOW_BARS_BY_SWIPE
        }
	    ...
	}

BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE

非表示にされたSystem Barは画面の上端または下端からのスワイプで再表示(黒の半透明)されます。ただし、一定時間の経過後に再び非表示になります。

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        ...
        window.decorView.windowInsetsController?.apply {
            hide(WindowInsets.Type.systemBars())
            systemBarsBehavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
        }
	    ...
	}
スポンサーリンク

System Barの背面へコンテンツ表示

通常、System Barとコンテンツは重なり合いません。この重なり合いを許して、System Barの背面へコンテンツの表示が可能です。

方法はWindow#setDecorFitsSystemWindowsでfalseを指定します。setDecorFitsSystemWindows( )はApi30で追加になったメソッドです。

ただし、Sysytem Barを半透明にする必要があります。System Barの背面にあるコンテンツが見えなければ、意味が無いからです。

背面へコンテンツを表示する実行例です。

背面へ表示する様子は子Viewのレイアウト属性を参照してください。layout_marginとpaddingとgravityを使って実現されている事が分かります。

setDecorFitsSystemWindowsでfalse指定

System Barの背面にContents Viewが表示されます。

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        ...
	    window.setDecorFitsSystemWindows(false)
	    ...
		// System Barの背景の透明度を変更
		val _SystemBarColor = ContextCompat.getColor(this, R.color.barback)
        window.navigationBarColor = _SystemBarColor
        window.statusBarColor = _SystemBarColor
	    ...
	}
<?xml version="1.0" encoding="utf-8"?>
<resources>
    ...
    <color name="barback">#50ffffff</color>
	...
</resources>
【setDecorFitsSystemWindowsでfalse指定】

setDecorFitsSystemWindowsでfalse指定
※LTRB : Left,Top,Right,Bottom
【子Viewのレイアウト属性】

Class = DecorView
  Class = LinearLayout
    Position = (0, 0)
    Size     = 320x480
    Layout Width, Height = -1,-1
    Layout Margin LTRB   = 0,0,0,0
    Layout Gravity       = -1
    Padding LTRB         = 0,0,0,0
    Visibility           = 0
  Class = View
    Position = (0, 432)
    Size     = 320x48
    Layout Width, Height = -1,48
    Layout Margin LTRB   = 0,0,0,0
    Layout Gravity       = 80
    Padding LTRB         = 0,0,0,0
    Visibility           = 0
  Class = View
    Position = (0, 0)
    Size     = 320x24
    Layout Width, Height = -1,24
    Layout Margin LTRB   = 0,0,0,0
    Layout Gravity       = 48
    Padding LTRB         = 0,0,0,0
    Visibility           = 0
スポンサーリンク

関連記事:

System Barはプログラマ側で記述をしなくても、デフォルトでアプリケーション画面に表示されます。 何処かで表示されるような構成になっているのです。 System Barが表示される仕組みを調べたので紹介します。 ...
アプリケーションの種類によってはSystem Barを非表示にしたい場合があります。 例えば、没入したいゲームはStatus Barを非表示にして、システムからの割り込みを無くすことが望ましいでしょう。 System Barはデフォルトでアプリに表示されますが、プログラムで非表示にすることも可能です。 System Barの表示・非表示の制御について紹介します。 ...
フルスクリーン(全画面モード)でコンテンツを提供することに適したアプリケーションがあります。 例えば、動画プレーヤー、ゲーム、電子書籍リーダ、画像エディター、スライドショーなどです。 アンドロイドはフルスクリーンを3つのモードに分類しています。 ...
エッジ―ツーエッジ(EdgeToEdge)について、まとめます。 エッジ―ツーエッジは言葉の通りに解釈すれば「端から端まで」ですから、見た目はフルスクリーンです。 しかし、新たな画面構成であり、フルスクリーンとは別物と定義されています。 最近は、様々なスクリーン形状を持つ端末が登場しています。 それらで、マルチウィンドウを実現するために、エッジツーエッジの対応が必須の条件になるようです。APIがエッジツーエッジを前提に作られているためです。 ですので、エッジ―ツーエッジは、今後のアプリ開発で重要な技術要素と言えます。 ※マルチウィンドウ:分割画面、フリーフォーム、PinP ※環境:Android Studio Jellyfish | 2023.3.1 Patch 1     Kotlin 1.9.0     Compose Compiler 1.5.1     androidx.appcompat:appcompat 1.6.1 ...
スポンサーリンク