Jetpack系列之Compose Scaffold

(一)概述

Scaffold 是 Material Design 提供的一个页面骨架组件,用于统一管理:TopAppBar(顶部栏),BottomBar(底部栏),FloatingActionButton(悬浮按钮),Snackbar,Drawer(侧边栏),主内容区(Content)。可以把 Scaffold 理解为:Compose 页面级布局的"地基"。Scaffold可以自动处理 Insets / padding,统一了页面结构, 与 TopAppBar / SnackbarHost 深度配合。总之,Scaffold 是 Compose 页面级布局的标准入口,负责"结构",而不是"内容"。

(二)Scaffold 属性说明

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
) {
    // 创建一个可变的窗口inset对象
    // remember:缓存计算结果,当 contentWindowInsets 变化时重新计算
    // MutableWindowInsets:可变的窗口inset,用于动态调整inset区域
    val safeInsets = remember(contentWindowInsets) { MutableWindowInsets(contentWindowInsets) }
    // Surface:Material Design 的表面组件,提供颜色、形状等特性
    Surface(
        modifier =
            // 监听已经被消耗的窗口inset
            modifier.onConsumedWindowInsetsChanged { consumedWindowInsets ->
                // Exclude currently consumed window insets from user provided contentWindowInsets
                safeInsets.insets = contentWindowInsets.exclude(consumedWindowInsets)
            },
        // 设置表面颜色和内容颜色
        color = containerColor,
        contentColor = contentColor
    ) {
        // ScaffoldLayout:实际的布局组件,负责排列各个部分
        ScaffoldLayout(
            fabPosition = floatingActionButtonPosition,
            topBar = topBar,
            bottomBar = bottomBar,
            content = content,
            snackbar = snackbarHost,
            contentWindowInsets = safeInsets,
            fab = floatingActionButton
        )
    }
}

modifier - 修饰符,用于调整布局大小、位置等。

topBar - 顶部栏(如 AppBar),通常是 TopAppBar。

bottomBar - 底部栏(如 BottomNavigation)。

snackbarHost - Snackbar 容器,用于显示提示信息。

floatingActionButton - 悬浮操作按钮(FAB)。

floatingActionButtonPosition - FAB 位置,默认右侧,FabPosition.End - 右侧(RTL 布局时是左侧),FabPosition.Center - 居中。

containerColor - Scaffold 容器背景色,默认使用主题的背景色。

contentColor - 内容颜色,自动根据容器颜色计算对比色。

contentWindowInsets - 内容区域的窗口Inset(处理状态栏、导航栏等)。

content - 主要内容区域,接收 PaddingValues 来避免内容被遮挡。

(三)Scaffold 封装

Kotlin 复制代码
package com.leo.wechat.utils

import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.luminance
import com.google.accompanist.systemuicontroller.rememberSystemUiController

@Composable
fun SystemBarController(
    backgroundColor: Color,
    contentColor: Color,
) {
    // 根据内容颜色的明暗,自动判断系统状态栏 / 导航栏图标是用深色还是浅色
    val darkIcons = contentColor.luminance() < 0.5f

    // implementation 'com.google.accompanist:accompanist-systemuicontroller:0.32.0'
    val systemUiController = rememberSystemUiController()
    SideEffect {
        systemUiController.setStatusBarColor(
            color = backgroundColor,
            darkIcons = darkIcons
        )
        systemUiController.setNavigationBarColor(
            color = backgroundColor,
            darkIcons = darkIcons
        )
    }
}

SystemBarController.kt 说明:封装系统状态栏 / 导航栏图标是用深色还是浅色
Kotlin 复制代码
package com.leo.wechat.ui.component.scaffold

import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import com.leo.wechat.ui.component.topbar.AppTopBar
import com.leo.wechat.ui.component.topbar.AppTopBarIcon
import com.leo.wechat.utils.SystemBarController

/* StatusBar / TopBar / 页面背景 自动统一 */
@Composable
fun AppScaffold(
    title: String,
    modifier: Modifier = Modifier,
    startIcon: AppTopBarIcon? = null,
    endIcon: AppTopBarIcon? = null,
    backgroundColor: Color = MaterialTheme.colorScheme.background,
    contentColor: Color = MaterialTheme.colorScheme.onBackground,
    content: @Composable (PaddingValues) -> Unit,
) {
    SystemBarController(
        backgroundColor = backgroundColor,
        contentColor = contentColor
    )

    Scaffold(
        modifier = modifier.fillMaxSize(),
        topBar = {
            AppTopBar(
                title = title,
                /**
                 * Modifier.statusBarsPadding() 的作用是:
                 * 给 Composable 自动加上"状态栏高度"的内边距,避免内容被状态栏遮挡。
                 * Modifier.statusBarsPadding() 等价于:Modifier.padding(top = statusBarHeight)
                 */
                modifier = Modifier.statusBarsPadding(),
                backgroundColor = backgroundColor,
                contentColor = contentColor,
                startIcon = startIcon,
                endIcon = endIcon
            )
        },
        containerColor = backgroundColor
    ) { innerPadding ->
        content(innerPadding)
    }
}

AppScaffold.kt 说明:支持StatusBar / TopBar / 页面背景 自动统一,支持左右Icon按钮的TopBar
Kotlin 复制代码
// 替代传统的 AppCompatActivity + XML
class MainActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // 创建 Compose UI 树,替代 setContentView(R.layout.xxx),
        // 内部是一个 Composable Scope(只要 State 变化,里面的 Composable 会自动重组)。
        setContent {
            // 控制全局主题(浅色 / 深色 等),所有 UI 都应该在 ComposeTheme 内部。
            ComposeTheme {
                // Context 只在需要它的最小 Composable 作用域中获取
                val context = LocalContext.current
                // 自定义布局架构
                AppScaffold(
                    title = "微信",
                    startIcon = AppTopBarIcons.back { finish() },
                    endIcon = AppTopBarIcons.more {
                        Toast.makeText(context, "更多", Toast.LENGTH_SHORT).show()
                    }
                ) { innerPadding ->

                    /**
                     * 在自定义 AppScaffold 或 Scaffold 中:
                     *  content 区域如果不消费 innerPadding,内容会被 layout 到 0 size 或被 top bar 覆盖。
                     */
                }
            }
        }
    }
}

MainActivity.kt 说明: 主页面,使用 Compose 替代传统的 AppCompatActivity + XML 写法。
相关推荐
2501_944424122 小时前
Flutter for OpenHarmony游戏集合App实战之数字拼图打乱排列
android·开发语言·flutter·游戏·harmonyos
文 丰2 小时前
【Android Studio】gradle下载慢解决方案(替换配置-非手工下载安装包)
android·ide·android studio
2501_944526423 小时前
Flutter for OpenHarmony 万能游戏库App实战 - 知识问答游戏实现
android·开发语言·javascript·python·flutter·游戏·harmonyos
路人与大师3 小时前
[深度架构] 拒绝 Prompt 爆炸:LLM Skills 的数学本质与“上下文压缩”工程论
android·架构·prompt
zhangphil3 小时前
Android系统如何把Bitmap通过RenderThread及GPU器件显示到屏幕
android
2501_944424123 小时前
Flutter for OpenHarmony游戏集合App实战之数字拼图滑动交换
android·开发语言·flutter·游戏·harmonyos
a3158238063 小时前
Android编码规范(修订版)
android·代码规范
灵感菇_3 小时前
Android OkHttp框架全解析
android·java·okhttp·网络编程
w***76553 小时前
快速上手DCAT-Admin开发指南
android