You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何根据AppBar自动为Android状态栏着色(Material 3规范)

Material 3 滚动时同步 AppBar 与状态栏颜色的实现方案

核心思路

要实现滚动时AppBar和状态栏颜色同步适配,关键是让状态栏颜色跟随AppBar的滚动状态动态变化,而非单独设置固定色。Material 3的Top App Bar滚动行为本身会跟踪滚动偏移量,我们可以基于这个偏移量计算颜色透明度,同步应用到状态栏和AppBar上。

具体实现(Jetpack Compose)

1. 初始化滚动行为

先创建TopAppBarScrollBehavior,它负责跟踪列表滚动的偏移状态:

val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())

2. 动态计算同步颜色

通过滚动偏移量计算透明度比例,将这个比例同时应用到AppBar和状态栏的背景色:

val scrollOffset = scrollBehavior.state.offset
// 计算滚动进度对应的透明度,限制在0-1之间
val alpha = (scrollOffset / scrollBehavior.state.height).coerceIn(0f, 1f)
// 基于主题主色生成带透明度的颜色
val syncColor = MaterialTheme.colorScheme.primary.copy(alpha = alpha)

3. 同步更新状态栏与AppBar

使用SystemUiController动态更新状态栏颜色,同时把计算好的颜色传给TopAppBar:

val systemUiController = rememberSystemUiController()
// 透明度变化时更新状态栏
LaunchedEffect(alpha) {
    systemUiController.setStatusBarColor(
        color = syncColor,
        // 根据主题亮度切换状态栏图标颜色
        darkIcons = !MaterialTheme.colorScheme.isLight
    )
}

// 配置TopAppBar,使用同步后的颜色
TopAppBar(
    title = { Text("页面标题") },
    scrollBehavior = scrollBehavior,
    colors = TopAppBarDefaults.topAppBarColors(
        containerColor = syncColor,
        titleContentColor = MaterialTheme.colorScheme.onPrimary.copy(alpha = alpha)
    )
)

4. 绑定列表滚动事件

将滚动行为关联到列表的nestedScroll修饰符,让列表滚动触发AppBar的状态变化:

LazyColumn(
    modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection)
) {
    // 列表内容
    items(50) { index ->
        Text("列表项 $index", modifier = Modifier.padding(16.dp))
    }
}

避免每个页面重复处理:封装全局组件

为了不用在每个页面写重复逻辑,把上述逻辑封装成一个可复用的组件:

@Composable
fun SyncScrollTopAppBar(
    title: String,
    scrollBehavior: TopAppBarScrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState()),
    content: @Composable () -> Unit
) {
    val systemUiController = rememberSystemUiController()
    val scrollOffset = scrollBehavior.state.offset
    val alpha = (scrollOffset / scrollBehavior.state.height).coerceIn(0f, 1f)
    val syncColor = MaterialTheme.colorScheme.primary.copy(alpha = alpha)

    LaunchedEffect(alpha) {
        systemUiController.setStatusBarColor(
            color = syncColor,
            darkIcons = !MaterialTheme.colorScheme.isLight
        )
    }

    Scaffold(
        topBar = {
            TopAppBar(
                title = { Text(title) },
                scrollBehavior = scrollBehavior,
                colors = TopAppBarDefaults.topAppBarColors(
                    containerColor = syncColor,
                    titleContentColor = MaterialTheme.colorScheme.onPrimary.copy(alpha = alpha)
                )
            )
        }
    ) { padding ->
        LazyColumn(
            modifier = Modifier
                .padding(padding)
                .nestedScroll(scrollBehavior.nestedScrollConnection)
        ) {
            content()
        }
    }
}

之后每个页面直接调用这个组件即可:

SyncScrollTopAppBar(title = "我的首页") {
    items(100) { index ->
        Text("内容项 $index", modifier = Modifier.padding(16.dp))
    }
}

View系统兼容方案(非Compose)

如果使用传统View系统,通过AppBarLayout.OnOffsetChangedListener监听滚动偏移,动态更新状态栏颜色:

appBarLayout.addOnOffsetChangedListener { _, verticalOffset ->
    val alpha = Math.abs(verticalOffset).toFloat() / appBarLayout.totalScrollRange
    val statusBarColor = ContextCompat.getColor(context, R.color.primary).adjustAlpha(alpha)
    window.statusBarColor = statusBarColor
    // 同时更新AppBar的背景色
    appBarLayout.setBackgroundColor(statusBarColor)
}

// 辅助方法:调整颜色透明度
fun Int.adjustAlpha(alpha: Float): Int {
    val red = Color.red(this)
    val green = Color.green(this)
    val blue = Color.blue(this)
    return Color.argb((alpha * 255).toInt(), red, green, blue)
}

内容的提问来源于stack exchange,提问作者David

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 14:02:46