问题描述
在KMP项目中,需要适配android和ios的沉浸式状态栏 适配需要解决几个问题
- 绘制区域 在安卓中有
普通绘制区域
和系统绘制区域
两种 系统绘制区域包括状态栏
和导航栏
在ios上主要处理状态栏 默认情况下是不会绘制到状态栏 和 导航栏的 所以我们首先要让画面绘制延伸到状态栏和导航栏 - 延伸之后 文字等组件可能显示在状态栏之上 我们需要调整边距使得组件正常显示,但是某些时候我们又需要让组件显示在状态栏之下,比如
播放器画面这个场景,所以需要根据实际业务调整。 - 除了调整边距之外,还需要适配 light 和 dark主题下 背景颜色下 状态栏文字颜色是否可见以及某些情况下是否隐藏状态栏。
解决办法
1. 绘制区域
安卓
在安卓中,我们可以通过设置enableEdgeToEdge()
来实现绘制区域的调整
kotlin
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 使得绘制区域延伸到屏幕边缘 包括 statusBar 和 navigationBar
enableEdgeToEdge()
// 设置内容
setContent {
App()
}
}
}
ios
在ios中,我们可以通过设置.ignoresSafeArea(edges: .all)
来实现绘制区域的调整
该文件默认为ContentView.swift
swift
import UIKit
import SwiftUI
import ComposeApp
struct ComposeView: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> UIViewController {
MainViewControllerKt.MainViewController()
}
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
}
struct ContentView: View {
var body: some View {
ComposeView()
.ignoresSafeArea(edges: .all) // 使得内容扩充到状态栏
.ignoresSafeArea(.keyboard) // Compose has own keyboard handler
}
}
2. 调整边距
安卓 IOS
因为我用的是KMP Compose material3组件中提供了Scaffold
组件,我们可以通过设置paddingValues
来调整边距
Scaffold 的content 中传入的innerPadding会自动计算状态栏高度。
kotlin
Scaffold(
topBar = {
TopAppBar(
title = { Text("ComposeApp") },
backgroundColor = MaterialTheme.colors.primary,
contentColor = Color.White,
elevation = 0.dp
)
},
content = { innerPadding->
// 设置paddingValues
Column(
modifier = Modifier.padding(innerPadding)
) {
// 设置内容
}
}
)
如果想要让组件显示在状态栏之下,可以通过设置传入一个自定义的空的WindowInsets来实现 传给
contentWindowInsets
即可
kotlin
@Composable
fun Scaffold(
modifier: Modifier = Modifier,
topBar: @Composable () -> Unit = {},
bottomBar: @Composable () -> Unit = {},
snackbarHost: @Composable () -> Unit = {},
floatingActionButton: @Composable () -> Unit = {},
floatingActionButtonPosition: FabPosition = FabPosition.End,
containerColor: Color = MaterialTheme.colorScheme.background,
contentColor: Color = contentColorFor(containerColor),
contentWindowInsets: WindowInsets = ScaffoldDefaults.contentWindowInsets,
content: @Composable (PaddingValues) -> Unit
) {
}

深色模式下适配情况
3. 适配 light 和 dark主题下 背景颜色下 状态栏文字颜色是否可见
参考以下代码
kotlin
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
installSplashScreen()
// 使得绘制区域延伸到屏幕边缘 包括 statusBar 和 navigationBar
enableEdgeToEdge()
// 设置内容
setContent {
ApplySystemBars()
App()
}
}
// 根据当前模式设置状态栏字体颜色
@Composable
fun ApplySystemBars(isDarkMode: Boolean = isSystemInDarkTheme()) {
val windowInsetsController = WindowInsetsControllerCompat(window, window.decorView)
LaunchedEffect(isDarkMode) {
if (isDarkMode) {
// 如果是深色模式,设置状态栏字体为浅色
windowInsetsController.isAppearanceLightStatusBars = false
} else {
// 如果是浅色模式,设置状态栏字体为深色
windowInsetsController.isAppearanceLightStatusBars = true
}
}
}
}