22 三步走实现 Compose 沉浸式状态栏

6,785 阅读1分钟

太简单了,直接来

这里有封装好的 22.3 Compose 沉浸式状态栏 Scaffold 封装

引用依赖:

implementation "androidx.compose.ui:ui:1.2.0"
implementation 'androidx.compose.material3:material3:1.1.0-rc01'
implementation "com.google.accompanist:accompanist-systemuicontroller:0.31.0-alpha"

第一步:让应用布局占满全屏

一行代码搞定

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        WindowCompat.setDecorFitsSystemWindows(window, false)
    }
51BE0386-C7F3-47AA-94A2-F66163CE2C72.png

设置后虽然应用布局高度可以占满全屏,但是由于状态栏和导航栏的 Window 级别高于应用的 Window 级别,所以应用布局仍然会被遮挡

第二步:设置状态栏和导航栏背景颜色透明

两种方式,一种是 xml Theme 设置,一种是代码设置。咱们这里只用代码来设置。

引入 accompanist-systemuicontroller 库,目前的版本是 0.31.0-alpha

implementation "com.google.accompanist:accompanist-systemuicontroller:0.31.0-alpha"

使用 SystemUiController 提供的 api 来设置状态栏和导航栏透明

@Composable
fun TransparentSystemBars() {
    val systemUiController = rememberSystemUiController()
    val useDarkIcons = !isSystemInDarkTheme()
    SideEffect {
        systemUiController.setSystemBarsColor(
            color = Color.Transparent,
            darkIcons = useDarkIcons,
            isNavigationBarContrastEnforced = false,
    }
}         

也可以使用 systemUiController.setStatusBarColor() 或 systemUiController.setNavigationBarColor() 单独设置

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    WindowCompat.setDecorFitsSystemWindows(window, false)

    setContent {

        WindowInsetsDemoTheme {
            // A surface container using the 'background' color from the theme
            TransparentSystemBars()
            Box(modifier = Modifier.fillMaxSize().background(Color.Magenta),
            ) {
                LazyColumn(
                    verticalArrangement = Arrangement.spacedBy(22.dp)
                ) {
                    items(20) {
                        Text(text = "第 $it 项")
                    }
                }
            }
        }
    }
}
87B94FB4-97E3-4AB2-B168-C05252B01B63.png

需要注意 TransparentSystemBars() 方法需要放在 Theme 的 content 中调用,不然状态栏还有导航栏的颜色还是 Theme colorScheme 中设置的颜色

第三步:处理 WindowInsets

e2e-intro.gif

Compose 1.2.0 之后已经将 Accompanist-Insets 添加到 androidx.compose.foundation 中了,所以可以在 Compose 中直接使用 。


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        WindowCompat.setDecorFitsSystemWindows(window, false)

        setContent {

            WindowInsetsDemoTheme {
                TransparentSystemBars()
                Box(
                    modifier = Modifier.fillMaxSize().background(Color.Magenta)
                        .systemBarsPadding() //同时添加状态栏和导航栏高度对应的上下 padding
//                        .statusBarsPadding() //只添加状态栏
//                        .navigationBarsPadding()//只添加导航啦
                ) {
                    LazyColumn(
                        verticalArrangement = Arrangement.spacedBy(22.dp)
                    ) {
                        items(20) {
                            Text(text = "第 $it 项")
                        }
                    }
                }
            }
        }
    }

436B85FB-8E78-4DC7-8E57-1327E53064B6.png

Compose M3 1.1.0 后 Scaffold、AppTopBar 、AppBottom 默认添加了 WindowInsets 支持,使用时不需要再特别处理 WindowInsets。

@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
) 

最简单的沉浸式状态栏

Scaffold(
        topBar = {
            CenterAlignedTopAppBar(
                colors = TopAppBarDefaults.centerAlignedTopAppBarColors(
                    containerColor = Color.Blue
                ),
                title = { Text(text = "WindowInsets") }
            )
        },
        bottomBar = {
            BottomAppBar(containerColor = Color.Green) {}
        }
    ) { paddingValues ->
      //...  
}
576967E5-504A-4779-8046-C71A19E84683.png

实现方式这三步就搞定了,具体实现看情况自己设置就好了,需要注意的就是 WindowInsets 的处理。