たくさんの自由帳

Hello Android 11。systemUiVisibility編

投稿日 : | 0 日前

文字数(だいたい) : 2688

よーこそtargetSdkVersion 30の世界へ

本題

Activityを全画面にしたり、ステータスバー、ナビゲーションを一時的に消すときにwindow?.decorView?.systemUiVisibilityがAndroid 11から非推奨になった
代わりにWindowInsetsControllerを使って消すらしい。

環境

なまえあたい
端末Pixel 3 XL
Android11 Beta 1

非表示の種類

  • スワイプすることで一時的にはステータスバー、ナビゲーションバーが表示され、数秒操作しないとまた自動で全画面に戻る
    • 動画アプリとか
    • WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPEを使う(後述)
  • スワイプして、ステータスバーを表示させるけどそのまま表示したままになる
    • どこで使ってるかはわからんな
    • WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPEを使う(後述)

追記

Android 6 以降ならAndroidX(androix.から始まるパッケージ、クラスの最後にCompatがつく)によるバックポートがあるのでそれを使えばいいと思います。
WindowInsetsControllerもAndroid 11から追加されたAPIですが、AndroidX(旧称:サポートライブラリ)を利用することでAndroid 6から対応することができます。

/**
 * キーボードを非表示にする。
 *
 * IMEで思い出した。XperiaのPOBox Plus返して。あれ使いやすかったのに
 *
 * @param activity Activity
 * */
fun hideKeyboard(activity: Activity) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        val insetsControllerCompat = WindowInsetsControllerCompat(activity.window, activity.window.decorView)
        insetsControllerCompat.hide(WindowInsetsCompat.Type.ime())
    }
}

つくる

スワイプすると一時的に表示される方
一時的に表示しているバーは半透明になっている。

supportActionBar?.hide()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    // ステータスバーの後ろにViewを潜らせるならこれも
    window?.setDecorFitsSystemWindows(false)
    // Android 11 以上と分岐
    window?.insetsController?.apply {
        // StatusBar + NavigationBar 非表示
        hide(WindowInsets.Type.systemBars())
        // スワイプで一時的に表示可能
        systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
        // ノッチにも侵略
        window?.attributes?.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
    }
} else {
    // Android 10 以前。
    window?.decorView?.systemUiVisibility = View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
}

ノッチまでは広げなくていい場合は、ノッチにも侵略の一行をコメントアウトしてね。

もし一時的に表示ではなく、一回表示したらずっと出っぱなしにする際はsystemBarsBehavior

systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE

にすればいいと思います。

Type#systemBars()を使うと、ステータスバーとナビゲーションバーを消しますが、別に以下のコードでも動きます。

// ステータスバー
hide(WindowInsets.Type.statusBars())
// ナビゲーションバー
hide(WindowInsets.Type.navigationBars())

おまけ

IME(キーボードのこと)もこのWindowInsetsControllerを利用することで、一行で消せるようになりました。

window?.insetsController?.hide(WindowInsets.Type.ime())

キーボード隠すのなんか面倒だし成功したことないからこの方法が使えるのは嬉しい。🥳