Jetpack Compose 实现全面屏显示技巧
要实现全面屏显示,本质上是对系统窗口行为进行配置,这与 View 或 Compose 的渲染机制无关。其原理和传统 View 系统完全一致,使用的 API 也相同。不过,在 Compose 环境下,代码组织方式有所差异。
首先查看默认生成的主题配置:
@Composable
fun HelloComposeTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
dynamicColor: Boolean = true,
content: @Composable () -> Unit
) {
val colorScheme = when {
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val context = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
}
darkTheme -> DarkColorScheme
else -> LightColorScheme
}
val view = LocalView.current
if (!view.isInEditMode) {
SideEffect {
val window = (view.context as Activity).window
window.statusBarColor = colorScheme.primary.toArgb()
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme
}
}
MaterialTheme(
colorScheme = colorScheme,
typography = Typography,
content = content
)
}
以上代码中处理状态栏和导航栏的部分原为:
val window = (view.context as Activity).window
window.statusBarColor = colorScheme.primary.toArgb()
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme
现在将其修改为全面屏模式:
val view = LocalView.current
if (!view.isInEditMode) {
SideEffect {
val window = (view.context as Activity).window
// 清空状态栏和导航栏背景色,使其透明
window.statusBarColor = android.graphics.Color.TRANSPARENT
window.navigationBarColor = android.graphics.Color.TRANSPARENT
// 允许内容绘制到系统栏后方区域
WindowCompat.setDecorFitsSystemWindows(window, false)
// 根据主题控制状态栏内容的明亮模式:true 为深色图标,false 为浅色图标
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme
// 移除导航栏默认的半透明遮罩层
window.isNavigationBarContrastEnforced = false
}
}
实际开发中,虽然希望内容背景扩展到系统栏下方,但又不希望内容被系统栏遮挡。通常做法是:为顶层容器设置背景色,并留出系统栏所需的边距——上边距为状态栏高度,下边距为导航栏高度。
在传统 View 体系中有两种常用方法:
- 动态获取状态栏和导航栏高度,然后在 Activity 中注册监听,在回调中动态调整布局。
- 在 XML 根布局中设置
android:fitsSystemWindows="true"。
在 Compose 中,更简单的做法是利用 Modifier 系统提供的 Modifier.systemBarsPadding() 方法,它可以自动为可组合项添加系统栏所需的边距:
@Composable
fun FullScreenContent() {
Box(
modifier = Modifier
.fillMaxSize()
.background(colorScheme.background)
.systemBarsPadding() // 自动处理状态栏和导航栏边距
) {
// 这里放置不会被系统栏遮挡的内容
}
}
至此,只要在主题中配置好窗口属性,并在顶层容器上应用 .systemBarsPadding(),即可轻松实现内容延伸到系统栏区域且不被遮挡的全面屏效果。
