【Compose 系列】第 4 篇:布局与 Modifier,写界面不走弯路

定位:入门 / 常用技能 适合:能写单个组件,但一排版就乱、Modifier 顺序总是搞反的同学


一、Compose 布局的心智:先「测量」后「摆放」

Compose 的布局分三步:测量 → 摆放 → 绘制 ,而且有个铁律:每个子组件只被测量一次 。这一点和传统 View 的 onMeasure(父子可以来回协商多次)很不一样。

对小白来说,你只需要记住三块积木,能解决 90% 的排版:

  • Column:竖着排(垂直方向)。
  • Row:横着排(水平方向)。
  • Box:叠着排(类似 FrameLayout,后写的盖在前写的上面)。

配合 Modifier(修饰符)控制大小、边距、背景、点击等。


二、Modifier 顺序:最容易踩的坑

Modifier 可以链式调用,但顺序会显著影响结果。看这个经典案例:

kotlin 复制代码
// 案例 A:先 padding,再 background
Box(
    modifier = Modifier
        .padding(20.dp)
        .background(Color.Red)
)

// 案例 B:先 background,再 padding
Box(
    modifier = Modifier
        .background(Color.Red)
        .padding(20.dp)
)

结果完全不同:

  • 案例 A:先在四周留出 20dp 空白,再在剩余区域画红色背景。红色区域被 padding 挤小了。
  • 案例 B:先画满红色背景,再在红色内部留 20dp 空白。红色区域撑满原尺寸。

一句话记忆:Modifier 是从外到内、从左到右依次「包裹」的。左边的先作用在外层,右边的作用在内层。

想清楚这条,size、clickable、clip 等顺序问题都能自己推出来。


三、常用布局速查表

需求 用什么 关键参数
竖排 Column verticalArrangement(主轴间距)、horizontalAlignment(交叉轴对齐)
横排 Row horizontalArrangement、verticalAlignment
叠放/定位 Box Alignment
复杂约束 ConstraintLayout createRefs、约束关系
铺满 Modifier.fillMaxSize() 注意 fillMaxWidth/fillMaxHeight
间距 Modifier.padding() 四边或单边
宽高 Modifier.size(width, height) 固定尺寸

Arrangement 控制主轴上的间距(SpaceBetween、SpaceAround、spacedBy),Alignment 控制交叉轴上的对齐。这两个词区分清楚,排版就通了一半。


四、Scaffold:页面的「骨架」

写一个标准页面,别从零堆 Column,直接用 Scaffold。它帮你准备好 TopBar(顶栏)、BottomBar(底栏)、FloatingActionButton(悬浮按钮)和内容区。

kotlin 复制代码
Scaffold(
    topBar = { TopAppBar(title = { Text("标题") }) },
    bottomBar = { BottomAppBar { Text("底栏") } },
    floatingActionButton = { FloatingActionButton(onClick = {}) { Text("+") } }
) { innerPadding ->
    // 内容区:务必应用 innerPadding,否则会被系统栏/顶栏挡住
    Column(modifier = Modifier.padding(innerPadding)) {
        Text("页面内容")
    }
}

小白最容易忘的是 innerPadding :Scaffold 的 lambda 会传给你一个 PaddingValues,它包含了顶栏、底栏、系统状态栏占用的空间。内容区一定要 Modifier.padding(innerPadding),否则内容会被遮挡。


五、Material 3 主题:一套配色吃遍天下

Compose 默认基于 Material 3 。你不需要手写颜色值,而是通过 MaterialTheme.colorScheme 取语义化颜色:

kotlin 复制代码
Text(color = MaterialTheme.colorScheme.primary)          // 主色
Surface(color = MaterialTheme.colorScheme.surface)       // 表面色

好处:换主题(浅色/深色)时,整套颜色自动切换。做暗黑模式几乎零成本。MaterialTheme 是文章 demo 里到处出现的外层包裹,本质就是给子树提供「主题环境」。


六、资深开发者的醍醐灌顶时刻

  1. Compose 的布局不是 ViewGroup 的翻版 。没有 onMeasure 的多轮协商,测量是单遍的。这意味着自定义布局要自己实现测量逻辑 (第 11 篇),但也避免了 View 体系里 MeasureSpec 的坑。
  2. Modifier 是「不可变链」。每个 Modifier 都是一个包装对象,链式调用会生成嵌套结构。顺序决定嵌套层级,所以顺序即语义。
  3. padding 在 clickable 前后,点击区域不同 :clickable 在外层时,padding 区域也可点击;clickable 在内层时,padding 区域不可点击。这是一个真实生产 bug 高发点。
  4. 别滥用 Box 做绝对定位 。优先用 Column/Row + Arrangement/Alignment,语义更清晰,也更容易适配不同屏幕。

七、动手题

写一个「个人信息卡片」:头像圆形、姓名在右侧、下方一行简介,整体卡片有圆角、阴影、内边距。用 Row、Column、Box 和 Modifier 完成,特别注意 Modifier 顺序。


八、学习资料

(下一篇预告:状态管理进阶,StateFlow + ViewModel 的工程级架构。)

相关推荐
天空之城--1 天前
Android一周动态:Android 18首次官宣、Compose Material3 1.4转正(5趋势+5资讯)
android·人工智能·flutter·架构·android jetpack
传奇开心果编程2 天前
【现代声明式UI学与练】第1课 从命令式UI到声明式UI
学习·flutter·ui·swiftui·react·android jetpack
传奇开心果编程5 天前
【用案例学Material 3 Expressive】第1课:从一封邮件开始,感受安卓设计新语言的表现力
android·学习·ui·kotlin·android jetpack
传奇开心果编程5 天前
【Jetpack Compose进阶学与练】第14课:系列收尾复习总结;Compose项目常见坑点汇总;学习路线与后续学习方向
android·学习·ui·kotlin·android jetpack
hai_android6 天前
子 View 被压小时,如何向父容器"告状"?——MEASURED_STATE_TOO_SMALL 向上传递机制
android·kotlin·android jetpack
alexhilton6 天前
生命周期感知的多模块启动模式
android·kotlin·android jetpack
hai_android7 天前
RecyclerView 缓存机制详解
android·kotlin·android jetpack
hai_android7 天前
深入理解 Java 的四种引用:强引用、软引用、弱引用、虚引用
android·kotlin·android jetpack
zbmwa7 天前
jetpack compose 副作用 SideEffect
android jetpack
alexhilton13 天前
藏在设备上的秘密,终究藏不住
android·kotlin·android jetpack