API 30 からは全画面モードに使っていたsystemUiVisibilityが非推奨になりました。代わりに windowInsetsControlle を使いますが、下位互換ではないのでAPI29までは切り替えて使う必要があります。
API 29
Fullscreen
ゲームやギャラリーなどは全画面での表示が好まれるアプリです。単純に全画面にするとユーザーが困ることもあり、3つの方法がGoogleから提示されています。
コードでのfullscreenにはAPIが19以上という制約がありますが、API19未満のシェアは相当少なくなってきています。
例えば、この画像をフルスクリーンで表示したいとすると、
これを普通に表示させるとこうなります
フルスクリーンにするには3種類のバーを非表示にする必要があります。
- ステータスバー
- タイトルバー
- ナビゲーションバー
Enable fullscreen mode | Android Developers によると幾つかのアプローチがあると言っていますので、それぞれ試してみます。
Lean back
Lean backと言われている観賞モードです。ユーザーが画面を頻繁に操作しない例えば動画などでの全画面表示です。
setSystemUiVisibility() から status bar と navigation bar の設定で非表示にできます。
- SYSTEM_UI_FLAG_FULLSCREEN
- statusbarを非表示
- SYSTEM_UI_FLAG_HIDE_NAVIGATION
- navigationbarを非表示
また、全画面から戻ったり終了させるためには、画面をタップして戻ることが可能です。
このシステムバーの表示、非表示はリスナーを使ってステータスを知ることができます。
setOnSystemUiVisibilityChangeListener
なお、タイトルバーはここでは外しておくためにMainActivityの継承はActivity()とします。(AppCompatActivityは全画面表示モードで使います)
MainActivity.kt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
//package your.package.name //import androidx.appcompat.app.AppCompatActivity import android.app.Activity import android.os.Bundle import android.os.Build import android.view.View import android.util.Log //class MainActivity : AppCompatActivity() { class MainActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) leanBackMode() } @Suppress("DEPRECATION") private fun leanBackMode(){ val decorView = window.decorView decorView.systemUiVisibility = ( View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION ) window.decorView.setOnSystemUiVisibilityChangeListener { visibility -> // Note that system bars will only be "visible" if none of the // LOW_PROFILE, HIDE_NAVIGATION, or FULLSCREEN flags are set. if (visibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0) { Log.d("debug","The system bars are visible") } else { Log.d("debug","The system bars are NOT visible") } } } } |
あまり関係ないとは思いますがレイアウトです。
activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout 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:src="@drawable/img" android:scaleType="centerCrop" android:contentDescription="@string/app_name" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> |
起動時はフルスクリーンとなっており、”The system bars are NOT visible”のログが見て取れます。
画面タップで”The system bars are visible”とログが代わり、ステータスバーとナビゲーションバーが現れました。
没入モード
ゲームに没頭している(immersive)時に使うということでしょうか、
SYSTEM_UI_FLAG_IMMERSIVE
これを使うと画面を内側のスワイプダウンでフルスクリーンが解除されます。
- SYSTEM_UI_FLAG_IMMERSIVE
- SYSTEM_UI_FLAG_FULLSCREEN
- SYSTEM_UI_FLAG_HIDE_NAVIGATION
MainActivity.kt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
//package your.package.name //import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.app.Activity import android.os.Build import android.util.Log import android.view.View //class MainActivity : AppCompatActivity() { class MainActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) immersiveMode() } @Suppress("DEPRECATION") private fun immersiveMode(){ val decorView = window.decorView decorView.systemUiVisibility = ( View.SYSTEM_UI_FLAG_IMMERSIVE or View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION ) window.decorView.setOnSystemUiVisibilityChangeListener { visibility -> // Note that system bars will only be "visible" if none of the // LOW_PROFILE, HIDE_NAVIGATION, or FULLSCREEN flags are set. if (visibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0) { Log.d("debug","The system bars are visible") } else { Log.d("debug","The system bars are NOT visible") } } } } |
アプリ優先型没入モード
immersiveは、ゲームなどで頻繁に画面をスワイプするような場合などでシステムバー(ステータスバーやナビゲーションバー)が出てくると煩わしくなります。これを軽減するためにSYSTEM_UI_FLAG_IMMERSIVE_STICKYを使うことができます。
完全にはシステムバーにならない半透明な状態で何もしなければ数秒で元に戻ります。
- SYSTEM_UI_FLAG_IMMERSIVE_STICKY
- SYSTEM_UI_FLAG_FULLSCREEN
- SYSTEM_UI_FLAG_HIDE_NAVIGATION
MainActivity.kt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
//package your.package.name import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.app.Activity import android.os.Build import android.util.Log import android.view.View //class MainActivity : AppCompatActivity() { class MainActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) stickyImmersiveMode() } @Suppress("DEPRECATION") private fun stickyImmersiveMode(){ val decorView = window.decorView decorView.systemUiVisibility = ( View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION ) window.decorView.setOnSystemUiVisibilityChangeListener { visibility -> // Note that system bars will only be "visible" if none of the // LOW_PROFILE, HIDE_NAVIGATION, or FULLSCREEN flags are set. if (visibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0) { Log.d("debug","The system bars are visible") } else { Log.d("debug","The system bars are NOT visible") } } } } |
Fullscreen Mode
Activity()ではなくAppCompatActivity()を使いたい場合もあります。SYSTEM_UI_FLAG_LAYOUT_STABLE
を使うとタイトルバーを消せるのですが、これだけだと問題があります。
画面の status bar, navigation bar にスペースができてしまいます。これを解消するには
SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
これらはあたかもシステムバーが非表示であるかのようにビューをレイアウトしてくれるというものです。
- SYSTEM_UI_FLAG_IMMERSIVE_STICKY
- SYSTEM_UI_FLAG_FULLSCREEN
- SYSTEM_UI_FLAG_HIDE_NAVIGATION
- SYSTEM_UI_FLAG_LAYOUT_STABLE
- SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
- SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
また、DialogやPop up メニューなどによってこれらが阻害されないように、onWindowFocusChanged(hasFocus: Boolean)を使って非表示を遅らせることが必要な場合もあります。
これらをまとめると、
MainActivity.kt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
//package your.package.name import androidx.appcompat.app.AppCompatActivity //import android.app.Activity import android.os.Bundle import android.os.Build import android.util.Log import android.view.View class MainActivity : AppCompatActivity() { //class MainActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } override fun onWindowFocusChanged(hasFocus: Boolean) { super.onWindowFocusChanged(hasFocus) hideSystemUI() } @Suppress("DEPRECATION") private fun hideSystemUI(){ val decorView = window.decorView decorView.systemUiVisibility = ( View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN ) window.decorView.setOnSystemUiVisibilityChangeListener { visibility -> // Note that system bars will only be "visible" if none of the // LOW_PROFILE, HIDE_NAVIGATION, or FULLSCREEN flags are set. if (visibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0) { Log.d("debug","The system bars are visible") } else { Log.d("debug","The system bars are NOT visible") } } } |
これでフルスクリーン表示ができました。
API30 以上は以下を参考にしてAPIで切り分けてください
References:
Enable fullscreen mode | Android Developers
Control the system UI visibility | Android Developers