System Bar:フルスクリーンモード(全画面モード)

投稿日:  更新日:

フルスクリーン(全画面モード)でコンテンツを提供することに適したアプリケーションがあります。

例えば、動画プレーヤー、ゲーム、電子書籍リーダ、画像エディター、スライドショーなどです。

アンドロイドはフルスクリーンを3つのモードに分類しています。

スポンサーリンク

フルスクリーンモード(全画面モード)

フルスクリーンは用途の違いにより、3つのモードに分類できます。

モード適したコンテンツ再表示する方法
(画面の操作)
アプリ例
鑑賞モード画面を頻繁に操作しないタップ動画プレーヤー
スライドショー
没入モード画面を頻繁に操作する上下端からスワイプゲーム
(キャラ移動を画面操作)
電子書籍リーダ
(ページ送りで画面操作)
アプリ優先型
没入モード
画面を頻繁に操作する上下端からスワイプ
・黒の半透明
・一定時間後に非表示
・アプリでも処理
画像エディター
(領域選択で画面操作)

フルスクリーンはSystem Barが非表示なので、携帯端末はそのアプリケーションのみを実行しているように振舞います。

しかし、通知のチェックやちょっとした検索など、ユーザの要求に応じた処理も行わなければなりません。

その時はフルスクリーンを終了し、システムにアクセスが可能な状態へ移行するため、System Barを再表示させます。

通常、System Barを再表示させる方法は画面の操作で行われ、モードに適したものが割り当てられます。

スポンサーリンク

鑑賞モード(Lead back mode)

画面を頻繁に操作しないコンテンツに適したモードです。

System Barを再表示する画面の操作は、簡素な「画面のタッチ」になります。

これは、System Barを再表示する画面の操作のみを考慮すればよいためです。

※System Barを非表示にする制御は次の記事を参照してください。

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

    override fun onResume() {
        super.onResume()
        hideSysBarInLeadBack()
    }

    // --------------------------------------------------------------
    private fun hideSysBarInLeadBack() {    // System Barを非表示
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            window.decorView.windowInsetsController?.apply {
                hide(WindowInsets.Type.systemBars())
                systemBarsBehavior = BEHAVIOR_SHOW_BARS_BY_TOUCH
            }
        } else {
            window.decorView.systemUiVisibility = (
                    SYSTEM_UI_FLAG_FULLSCREEN
                            or SYSTEM_UI_FLAG_HIDE_NAVIGATION
                    )
        }
    }

    private fun showSysBar() {              // System Barを表示
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            window.decorView.windowInsetsController?.apply {
                show(WindowInsets.Type.systemBars())
            }
        } else {
            window.decorView.systemUiVisibility = 0
        }
    }
※「≧Api30」の場合、タッチで再表示されるのはNavigation Barのみになります。Status Barはスワイプで再表示します。

スポンサーリンク

没入モード(Immersive mode)

画面を頻繁に操作するコンテンツに適したモードです。

System Barを再表示する画面の操作は、複雑さを持たせた「画面の上下端からのスワイプ」になります。

これは、コンテンツの操作とSystem barを再表示する操作を区別(同じにならないように)する必要があるためです。

System Barを非表示にする制御は次の記事を参照してください。

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

    override fun onResume() {
        super.onResume()
        hideSysBarInImmersive()
    }

    // --------------------------------------------------------------
    private fun hideSysBarInImmersive() {    // System Barを非表示
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            window.decorView.windowInsetsController?.apply {
                hide(WindowInsets.Type.systemBars())
                systemBarsBehavior = BEHAVIOR_SHOW_BARS_BY_SWIPE
            }
        } else {
            window.decorView.systemUiVisibility = (
                    SYSTEM_UI_FLAG_IMMERSIVE
                            or SYSTEM_UI_FLAG_FULLSCREEN
                            or SYSTEM_UI_FLAG_HIDE_NAVIGATION
                    )
        }
    }

    private fun showSysBar() {              // System Barを表示
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            window.decorView.windowInsetsController?.apply {
                show(WindowInsets.Type.systemBars())
            }
        } else {
            window.decorView.systemUiVisibility = 0
        }
    }
スポンサーリンク

アプリ優先型没入モード(Sticky immersive mode)

画面を頻繁に操作するコンテンツに適したモードです。

System Barを再表示する画面の操作は、複雑さを持たせた「画面の上下端からのスワイプ」になります。

ただし、コンテンツの操作とSystem barを再表示する操作を区別しません。両者に対する操作として受け付けます。

コンテンツの操作が優先して行われ、フルスクリーンが継続されます。フルスクリーンの表示を妨げないように、System Bar(黒の半透明)は一時的な再表示になります。

System Barを非表示にする制御は次の記事を参照してください。

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

    override fun onResume() {
        super.onResume()
        hideSysBarInStickImmersive()
    }

    // --------------------------------------------------------------
    private fun hideSysBarInStickImmersive() {    // System Barを非表示
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            window.decorView.windowInsetsController?.apply {
                hide(WindowInsets.Type.systemBars())
                systemBarsBehavior =
                    BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
            }
        } else {
            window.decorView.systemUiVisibility = (
                    SYSTEM_UI_FLAG_IMMERSIVE_STICKY
                        or View.SYSTEM_UI_FLAG_FULLSCREEN
                        or SYSTEM_UI_FLAG_HIDE_NAVIGATION
                    )
        }
    }

    private fun showSysBar() {              // System Barを表示
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            window.decorView.windowInsetsController?.apply {
                show(WindowInsets.Type.systemBars())
            }
        } else {
            window.decorView.systemUiVisibility = 0
        }
    }
スポンサーリンク

バックグラウンドから復帰でフルスクリーン

フルスクリーンの状態からActivityがバックグラウンドへ遷移すると、System Barの非表示は解除されてしまいます。ダイアログが表示された場合などが、これに当てはまります。

よって、再びフォアグラウンドに復帰した時、フルスクリーンになりません。

バックグラウンド遷移でSystem Bar非表示の解除

これを回避し、フルスクリーンを維持したければ、フォアグラウンドへ復帰する時点でSystem Barの非表示を再指定します。

回避方法1:onResumeで非表示を指定

フォアグラウンドへ復帰する時は必ずonResume( )が呼ばれるので、ここで非表示の指定を実行します。

    override fun onResume() {
        super.onResume()
        hideSysBarInXXX()	// System Barを非表示
    }

回避方法2:onWindowFocusChangedで非表示を指定

フォアグラウンドのViewが切り替わる時は必ずフォーカスの移動(変更)が伴います。このフォーカスの移動をトリガにして、非表示の指定を実行します。

    override fun onWindowFocusChanged(hasFocus: Boolean) {
        super.onWindowFocusChanged(hasFocus)
        if(hasFocus) {
            hideSysBarInXXX()	// System Barを非表示
        }
    }
スポンサーリンク

System Barの表示・非表示のイベント処理

System Barが表示・非表示になった時のイベント処理をしたければ、リスナーを登録します。

「≧Api30」と「<Api30」で使えるリスナーが異なっているので注意してください。

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            window.decorView.setOnApplyWindowInsetsListener(
                object : OnApplyWindowInsetsListener {
                    override fun onApplyWindowInsets(v: View, insets: WindowInsets)
                            : WindowInsets {
                        val _flag = (WindowInsets.Type.statusBars() or 
						                  WindowInsets.Type.navigationBars())
                        if(insets.isVisible(_flag)) // systemBars()は使用不可
                            // System Barが表示の時
                        else
                            // System Barが非表示の時
                        return v.onApplyWindowInsets(insets) // 下位へ実行を伝搬させる
                    }
                })
        }
        else {
            window.decorView.setOnSystemUiVisibilityChangeListener { visibility ->
                val _flag = (SYSTEM_UI_FLAG_FULLSCREEN or 
				                       SYSTEM_UI_FLAG_HIDE_NAVIGATION)
                if(visibility and _flag == 0)
                    // System Barが表示の時
                else
                    // System Barが非表示の時
            }
        }

「≧Api30」のリスナー登録

OnApplyWindowInsetsListenerを使います。「≧Api30」で追加になったクラスです。

WindowInsets#isVisible( )メソッドを用いてSystem Barの表示・非表示がチェックできます。

注意1:onApplyWindowInsets( )を実行

OnApplyWindowInsetsListenerを登録すると、onApplyWindowInsets( )の実行が子Viewへ伝搬しなくなります。

これは、登録した側のonApplyWindowInsets( )の実行が優先され、Viewが持つonApplyWindowInsets( )が実行されなくなるためです。

なので、リスナー中でViewが持つonApplyWindowInsets( )実行して伝搬を施します。

注意2:systemBars( )は使用不可

WindowInsets#isVisible( )の引数へsystemBars( )を用いると、System Barの表示・非表示に関係なくfalseが返ります。

なので、statusBars( )またはnavigationBars( )を用いるようにします。

「<Api30」のリスナー登録

OnSystemUiVisibilityChangeListenerを用います。「≧Api30」で非推奨になったクラスです。

System Barの表示・非表示の状態をvisibilityが持っています。

スポンサーリンク

関連記事:

System Barはプログラマ側で記述をしなくても、デフォルトでアプリケーション画面に表示されます。 何処かで表示されるような構成になっているのです。 System Barが表示される仕組みを調べたので紹介します。 ...
アプリケーションの種類によってはSystem Barを非表示にしたい場合があります。 例えば、没入したいゲームはStatus Barを非表示にして、システムからの割り込みを無くすことが望ましいでしょう。 System Barはデフォルトでアプリに表示されますが、プログラムで非表示にすることも可能です。 System Barの表示・非表示の制御について紹介します。 ...
アプリケーションの種類によってはSystem Barを非表示にしたい場合があります。 例えば、没入したいゲームはStatus Barを非表示にして、システムからの割り込みを無くすことが望ましいでしょう。 System Barはデフォルトでアプリに表示されますが、プログラムで非表示にすることも可能です。 System Barの表示・非表示の制御について紹介します。 ...
エッジ―ツーエッジ(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 ...
スポンサーリンク