KMP 适配 android ios 沉浸式状态栏


问题描述

在KMP项目中,需要适配android和ios的沉浸式状态栏 适配需要解决几个问题

  1. 绘制区域 在安卓中有普通绘制区域系统绘制区域 两种 系统绘制区域包括
    状态栏导航栏 在ios上主要处理状态栏 默认情况下是不会绘制到状态栏 和 导航栏的 所以我们首先要让画面绘制延伸到状态栏和导航栏
  2. 延伸之后 文字等组件可能显示在状态栏之上 我们需要调整边距使得组件正常显示,但是某些时候我们又需要让组件显示在状态栏之下,比如
    播放器画面这个场景,所以需要根据实际业务调整。
  3. 除了调整边距之外,还需要适配 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
            }
        }
    }
}

参考链接

  1. Jetpack Compose System UI 兼容以及沉浸式状态栏
  2. Status Bar Color Change in Compose Multiplatform

文章作者: Lao Wu
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Lao Wu !
评论
表情 | 预览
快来做第一个评论的人吧~
Powered By Valine
v1.3.10