ComponentActivityのenableEdgeToEdgeの動作を確認する
Activity v1.8.0からComponentActivityにenableEdgeToEdgeというメソッドが追加されて、EdgeToEdge対応が楽にできるという情報を得たので、簡単にですがコードと動作を確認してみたいと思います。
※ちなみに今回の動作確認では以下の依存関係を利用しています。
dependencies {
implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
implementation("androidx.activity:activity-compose:1.8.0")
implementation(platform("androidx.compose:compose-bom:2023.03.00"))
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-graphics")
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.compose.material3:material3")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
androidTestImplementation(platform("androidx.compose:compose-bom:2023.03.00"))
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest")
}
ComponentActivityのenableEdgeToEdgeのコードを見てみる
ComponentActivityのenableEdgeToEdgeのコードを見てみると各SDKバージョンごとに処理が分岐していることがわかる。そのため各SDKバージョンごとにEdgeToEdgeのセットアップに必要な処理が異なるということがわかる。
バージョン条件 | 呼び出す関数 |
---|---|
SDKバージョンが29以上 | EdgeToEdgeApi29 |
SDKバージョンが26〜28 | EdgeToEdgeApi26 |
SDKバージョンが23〜25 | EdgeToEdgeApi23 |
SDKバージョンが21〜22 | EdgeToEdgeApi22 |
SDKバージョンが20以下 | EdgeToEdgeBase |
@JvmName("enable")
@JvmOverloads
fun ComponentActivity.enableEdgeToEdge(
statusBarStyle: SystemBarStyle = SystemBarStyle.auto(Color.TRANSPARENT, Color.TRANSPARENT),
navigationBarStyle: SystemBarStyle = SystemBarStyle.auto(DefaultLightScrim, DefaultDarkScrim)
) {
val view = window.decorView
val statusBarIsDark = statusBarStyle.detectDarkMode(view.resources)
val navigationBarIsDark = navigationBarStyle.detectDarkMode(view.resources)
val impl = Impl ?: if (Build.VERSION.SDK_INT >= 29) {
EdgeToEdgeApi29()
} else if (Build.VERSION.SDK_INT >= 26) {
EdgeToEdgeApi26()
} else if (Build.VERSION.SDK_INT >= 23) {
EdgeToEdgeApi23()
} else if (Build.VERSION.SDK_INT >= 21) {
EdgeToEdgeApi21()
} else {
EdgeToEdgeBase()
}.also { Impl = it }
impl.setUp(
statusBarStyle, navigationBarStyle, window, view, statusBarIsDark, navigationBarIsDark
)
}
それぞれのSDKバージョンのEdgeToEdgeのコードを見てみる
それぞれのSDKバージョンのEdgeToEdgeのコードを見てみると、各SDKバージョンごとにStatusBarやNavigationBarの仕様が異なることがわかる。つまるところenableEdgeToEdgeは各SDKバージョンごとに異なるStatusBarとNavigationBarの仕様を吸収してくれる便利な関数らしい。
EdgeToEdgeApi29
@RequiresApi(29)
private class EdgeToEdgeApi29 : EdgeToEdgeImpl {
@DoNotInline
override fun setUp(
statusBarStyle: SystemBarStyle,
navigationBarStyle: SystemBarStyle,
window: Window,
view: View,
statusBarIsDark: Boolean,
navigationBarIsDark: Boolean
) {
// アプリを全画面で表示するようにする
WindowCompat.setDecorFitsSystemWindows(window, false)
// 指定したスクリムの色をStatusBarにセットする
window.statusBarColor = statusBarStyle.getScrimWithEnforcedContrast(statusBarIsDark)
// 指定したスクリムの色をNavigationBarにセットする
window.navigationBarColor =
navigationBarStyle.getScrimWithEnforcedContrast(navigationBarIsDark)
// 完全に透明な背景が要求された場合に、システムがステータスバーに十分なコントラストを確保しているかどうか
window.isStatusBarContrastEnforced = false
// 完全に透明な背景が要求された場合に、システムがナビゲーションバーに十分なコントラストを確保しているかどうか
window.isNavigationBarContrastEnforced =
navigationBarStyle.nightMode == UiModeManager.MODE_NIGHT_AUTO
WindowInsetsControllerCompat(window, view).run {
// ステータス・バーのフォアグラウンドがライトに設定するか
isAppearanceLightStatusBars = !statusBarIsDark
// ナビゲーションバーのフォアグラウンドがライトに設定するか
isAppearanceLightNavigationBars = !navigationBarIsDark
}
}
}
EdgeToEdgeApi26
@RequiresApi(26)
private class EdgeToEdgeApi26 : EdgeToEdgeImpl {
@DoNotInline
override fun setUp(
statusBarStyle: SystemBarStyle,
navigationBarStyle: SystemBarStyle,
window: Window,
view: View,
statusBarIsDark: Boolean,
navigationBarIsDark: Boolean
) {
// アプリを全画面で表示するようにする
WindowCompat.setDecorFitsSystemWindows(window, false)
// 指定したスクリムの色をStatusBarにセットする
window.statusBarColor = statusBarStyle.getScrim(statusBarIsDark)
// 指定したスクリムの色をNavigationBarにセットする
window.navigationBarColor = navigationBarStyle.getScrim(navigationBarIsDark)
WindowInsetsControllerCompat(window, view).run {
// ステータス・バーのフォアグラウンドがライトに設定するか
isAppearanceLightStatusBars = !statusBarIsDark
// ナビゲーションバーのフォアグラウンドがライトに設定するか
isAppearanceLightNavigationBars = !navigationBarIsDark
}
}
}
EdgeToEdgeApi23
@RequiresApi(23)
private class EdgeToEdgeApi23 : EdgeToEdgeImpl {
@DoNotInline
override fun setUp(
statusBarStyle: SystemBarStyle,
navigationBarStyle: SystemBarStyle,
window: Window,
view: View,
statusBarIsDark: Boolean,
navigationBarIsDark: Boolean
) {
// アプリを全画面で表示するようにする
WindowCompat.setDecorFitsSystemWindows(window, false)
// 指定したスクリムの色をStatusBarにセットする
window.statusBarColor = statusBarStyle.getScrim(statusBarIsDark)
// 指定したスクリムの色をNavigationBarにセットする
window.navigationBarColor = navigationBarStyle.darkScrim
// ステータス・バーのフォアグラウンドがライトに設定するか
WindowInsetsControllerCompat(window, view).isAppearanceLightStatusBars = !statusBarIsDark
}
}
EdgeToEdgeApi21
@RequiresApi(21)
private class EdgeToEdgeApi21 : EdgeToEdgeImpl {
@Suppress("DEPRECATION")
@DoNotInline
override fun setUp(
statusBarStyle: SystemBarStyle,
navigationBarStyle: SystemBarStyle,
window: Window,
view: View,
statusBarIsDark: Boolean,
navigationBarIsDark: Boolean
) {
// アプリを全画面で表示するようにする
WindowCompat.setDecorFitsSystemWindows(window, false)
// ステータスバーとナビゲーションバーを半透明にする
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
}
}
EdgeToEdgeBase
private class EdgeToEdgeBase : EdgeToEdgeImpl {
override fun setUp(
statusBarStyle: SystemBarStyle,
navigationBarStyle: SystemBarStyle,
window: Window,
view: View,
statusBarIsDark: Boolean,
navigationBarIsDark: Boolean
) {
// No edge-to-edge before SDK 21.
}
}
ComponentActivityのenableEdgeToEdgeの動作を確認する
なんとなくComponentActivityのenableEdgeToEdgeの動作がわかったので動作確認をしてみる。ちなみにstatusBarStyleとnavigationBarStyleのパラメータの型であるStatusBarStyleを変えることで、以下のように挙動を変えることができるみたいなので、これを変えながら動作確認をしてみる。
タイプ | パラメータ1 | パラメータ2 | パラメータ3 | 解説 |
---|---|---|---|---|
StatusBarStyle.light | scrim : 背景色 | darkScrim : 白いシステムアイコンしか端末が表示できない時に利用する背景色 | – | Scrimに明るい色が指定されることが想定される時に利用される(ライトモード) |
StatusBarStyle.dark | scrim : 背景色 | – | – | Scrimに暗い色が指定されることが想定される時に利用される(ダークモード) |
StatusBarStyle.auto | lightScrim : ライトモード時の背景色 | darkScrim: ダークモード時の背景色 | detectDarkMode : ライトモードとダークモードを検知する条件を定義 | ライトモード・ダークモードの切り替えに連動して色を変更したい時に利用する |
class SystemBarStyle private constructor(
private val lightScrim: Int,
internal val darkScrim: Int,
internal val nightMode: Int,
internal val detectDarkMode: (Resources) -> Boolean
) {
companion object {
@JvmStatic
@JvmOverloads
fun auto(
@ColorInt lightScrim: Int,
@ColorInt darkScrim: Int,
detectDarkMode: (Resources) -> Boolean = { resources ->
(resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) ==
Configuration.UI_MODE_NIGHT_YES
}
): SystemBarStyle {
return SystemBarStyle(
lightScrim = lightScrim,
darkScrim = darkScrim,
nightMode = UiModeManager.MODE_NIGHT_AUTO,
detectDarkMode = detectDarkMode
)
}
@JvmStatic
fun dark(@ColorInt scrim: Int): SystemBarStyle {
return SystemBarStyle(
lightScrim = scrim,
darkScrim = scrim,
nightMode = UiModeManager.MODE_NIGHT_YES,
detectDarkMode = { _ -> true }
)
}
@JvmStatic
fun light(@ColorInt scrim: Int, @ColorInt darkScrim: Int): SystemBarStyle {
return SystemBarStyle(
lightScrim = scrim,
darkScrim = darkScrim,
nightMode = UiModeManager.MODE_NIGHT_NO,
detectDarkMode = { _ -> false }
)
}
}
internal fun getScrim(isDark: Boolean) = if (isDark) darkScrim else lightScrim
internal fun getScrimWithEnforcedContrast(isDark: Boolean): Int {
return when {
nightMode == UiModeManager.MODE_NIGHT_AUTO -> Color.TRANSPARENT
isDark -> darkScrim
else -> lightScrim
}
}
}
SystemBarStyle.light
SystemBarStyle.lightを指定したときの動作を以下のコードで確認してみる。
enableEdgeToEdge(
statusBarStyle = SystemBarStyle.light(scrim = Color.RED, darkScrim = Color.BLUE),
navigationBarStyle = SystemBarStyle.light(scrim = Color.RED, darkScrim = Color.BLUE)
)
EdgeToEdgeApi29
- StatusBarとNavigationBarはScrimの色が反映されて赤色になる
EdgeToEdgeApi26
- StatusBarとNavigationBarはScrimの色が反映されて赤色になる
EdgeToEdgeApi23
- StatusBarはScrimの色が反映されて赤色になる
- NavigationBarはDarkScrimの色が反映されて青色になる
- システムアイコンが白色しか対応していないないのでDarkScrimが適用されるっぽい
EdgeToEdgeApi21
- StatusBarもNavigationBarもScrimの色は反映されずに半透明になる
- StatusBarやNavigationBartの背景色の指定ができないSDKバージョンのため
SystemBarStyle.dark
SystemBarStyle.darkを指定したときの動作を以下のコードで確認してみる。
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge(
statusBarStyle = SystemBarStyle.dark(scrim = Color.BLUE),
navigationBarStyle = SystemBarStyle.dark(scrim = Color.BLUE)
)
setContent {
Surface(modifier = Modifier.fillMaxSize()) {
LazyColumn(modifier = Modifier.fillMaxSize()) {
items(100) {
Text(text = it.toString())
}
}
}
}
}
}
EdgeToEdgeApi29
- StatusBarとNavigationBarはScrimの色が反映されて青色になる
EdgeToEdgeApi26
- StatusBarとNavigationBarはScrimの色が反映されて青色になる
EdgeToEdgeApi23
- StatusBarとNavigationBarはScrimの色が反映されて青色になる
- NavigationBarのシステムアイコンは白色のみしか対応していないが、暗い背景色が指定される想定なのでScrimに指定した色をそのまま描画
EdgeToEdgeApi21
- StatusBarもNavigationBarもScrimの色は反映されずに半透明になる
- StatusBarやNavigationBartの背景色の指定ができないSDKバージョンのため
SystemBarStyle.auto
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge(
statusBarStyle = SystemBarStyle.auto(lightScrim = Color.RED, darkScrim = Color.BLUE),
navigationBarStyle = SystemBarStyle.auto(
lightScrim = Color.GREEN,
darkScrim = Color.YELLOW
)
)
setContent {
MaterialTheme(
colorScheme = if(isSystemInDarkTheme()) darkColorScheme() else lightColorScheme()
) {
Surface(modifier = Modifier.fillMaxSize()) {
LazyColumn(modifier = Modifier.fillMaxSize()) {
items(100) {
Text(text = it.toString())
}
}
}
}
}
}
}
EdgeToEdgeApi29
- StatusBarとNavigationBarはScrimの色が反映されてライトモード・ダークモードかかわらず透明になる
- StatusBarStyle.autoにするとgetScrimWithEnforcedContrastでStatusBarとNavigationBarに設定するScrimの色が透明に強制的に指定されるためこのような動作になる。
EdgeToEdgeApi26
- StatusBarとNavigationBarはScrimの色が反映されてライトモードで赤色と青色、ダークモードで緑色と黄色になる
- ダークモードはSDKバージョン29のはずだが、SDKバージョン28のエミュレータだと動作した
EdgeToEdgeApi23
- StatusBarとNavigationBarはScrimの色が反映されて赤色・黄色になる
- ダークモードはSDKバージョン29から対応のため、切り替えての動作確認はできなかった。
EdgeToEdgeApi21
- StatusBarもNavigationBarもScrimの色は反映されずに半透明になる
- ダークモードはSDKバージョン29から対応のため、切り替えての動作確認はできなかった。
おわりに
- enableEdgeToEdgeを利用することでEdgeToEdge対応は比較的簡単にできるようになっている
- enableEdgeToEdgeに指定するStatusBarStyleによってStatusBarやNavigationBarの色が変わるようになっている。StatusBarやNavigationBarの色に関してはSDKバージョンごとに動作が異なるので注意が必要
参考記事
本ページの内容を書き終えた後に見つけたのですが、以下のページにAndroid OSバージョンごとにできるEdgeToEdge対応の方法論が書かれておりました。enableEdgeToEdgeはこの方針に基づいて作成されたものっぽいのでこちらの記事を参考に見てみるとさらに理解が深まるかなと思います。