一、从命令式到声明式
传统Android开发时代,我们都是这样写界面的:在XML里定义布局,在Activity里使用 findViewById 找到控件,然后调用 setXXXX 方法去更新UI。这就是命令式 写法,由开发者去告诉系统"怎么做"。
Jetpack Compose 则完全不同。我们不再需要告诉系统"怎么做 ",只需要告诉系统UI"长什么样 "。当数据状态变化时,界面会自动更新 。这就是声明式UI。
今天我们就来认识 Compose 最核心的两个概念:Composable 和 Modifier。
二、Composable------一切皆函数
在 Compose 中,所有的UI组件都是带有 @Composable 注解的 kotlin 函数。在上一篇中我们展示了Android Studio 自动生成的默认代码MainActivity.kt 里的一个Composable:
kotlin
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Text(
text = "Hello $name!",
modifier = modifier
)
}
//我们还可以将它改为最简单的一个Composable
@Composable
fun Greeting(name: String) {
Text(text = "Hello $name!")
}
该函数描述了这样的一个UI效果:一段显示问候语的文字。
Compose的运行可以划分两个阶段:
- 组合(Composition) :首次渲染时,UI框架执行所有
@Composable函数,生成一棵运行时的UI树。 - 重组(Recomposition):当状态发生变化时,框架重新执行受影响的Composable函数,但只更新变化的部分。
Compose 非常智能------它不会因为一个状态变化就把整个界面全部重绘一遍,而是只重组那些读取了变化状态的Composable。这正是Compose高效的原因。
下面请看一个例子,演示了Composable如何与状态配合工作:
kotlin
import androidx.compose.runtime.*
import androidx.compose.material3.*
import androidx.compose.ui.tooling.preview.Preview
@Composable
fun Counter() {
// 可观察状态
var count by remember { mutableStateOf(0) }
Column {
Text(text = "点击次数:$count", style = MaterialTheme.typography.headlineSmall)
Button(onClick = { count++ }) {
Text("点我")
}
}
}
@Preview
@Composable
fun PreviewCounter() {
Counter()
}
点击按钮,count 变化,只有 Text 所在的Composable会被重组,Button 本身不会被重新执行。
Compose
三、Modifier------修饰UI的利器
如果说Composable定义了UI"是什么",那么 Modifier 就定义了UI"长什么样、如何响应"。
Modifier 可以做到四类事情(常用的Modifier):
- 尺寸与布局:
padding()、fillMaxWidth()、size() - 外观样式:
background()、border() - 用户输入:
clickable()、draggable() - 交互行为:
scrollable()、semantics()
Modifier 最强大的地方在于链式调用------可以把多个修饰符串在一起:
kotlin
@Composable
fun UserCard(name: String) {
Column(
modifier = Modifier
.padding(16.dp) // 外间距
.fillMaxWidth() // 撑满宽度
.background(Color.LightGray, shape = RoundedCornerShape(8.dp))
.clickable { /* 点击处理 */ }
.padding(12.dp) // 内间距
) {
Text(text = name)
}
}
💡最佳实践
任何一个 Composable 函数都应该接受一个
modifier参数,并将其传递给第一个实际发出UI的子组件。这样可以使得组件具备良好的复用性。
四、Modifier的顺序
这是初学者最容易踩的坑:Modifier的顺序会影响最终结果。
原因在于,每个修饰符函数都会对前一个函数返回的 Modifier 进行包装。后面的修饰符包裹前面的修饰符,就像一层层洋葱皮。
下面看一个典型案例:
kotlin
Column(
modifier = Modifier
.clickable { /* 点击 */ }
.padding(16.dp)
)
clickable在前,padding在后,那么实际可点击区域是整个区域(包括了padding区域)。
但是如果反过来写:
kotlin
Column(
modifier = Modifier
.padding(16.dp)
.clickable { /* 点击 */ }
)
padding产生的空白区域就不可点击了,只有内容区域能响应点击。
我们在写Modifier时,要时刻想清楚"谁包裹谁":
- 若要点击区域更大,
clickable在前,padding在后。 - 若只想内容区域可点击,
padding在前,clickable在后。

五、总结
理解 Compose,抓住两个核心就够了:
- Composable 是用
@Composable注解的函数,描述 UI 是什么。状态变化时,只有受影响的 Composable 会被重组,保证高效。 - Modifier 是修饰 UI 的工具,通过链式调用调整尺寸、样式、行为和交互。顺序决定效果,写的时候要多加留意。
掌握了这两个概念,你就已经迈进了 Jetpack Compose 的大门。剩下的,就是在实践中不断熟悉各种 Composable 和 Modifier 的用法了。