Jetpack Compose 入门系列(一):从零搭建到基础控件使用
一、前言
一直用 XML + View 写界面?Jetpack Compose 是你该学的新方向。
1.1 什么是 Compose?
Jetpack Compose 是 Google 在 2021 年正式推出的 Android 原生声明式 UI 框架——它不依赖 XML,而是用 Kotlin 代码直接"描述"界面长什么样。
来做个对比你就明白了。以前用 XML + View 体系写界面,大致是三步走:
// 第一步:在 XML 里定义好布局
// 第二步:在 Activity 里 findViewById 找到控件
// 第三步:调用 setText()、setOnClickListener() 手动更新
这套模式叫命令式 UI——你得像下指令一样告诉程序每一步该做什么。而 Compose 的做法完全不同:
// 你只需要描述:"这里有一个文本,内容是 Hello"
Text(text = "Hello")
你说"界面应该长这样",框架自己判断什么时候该更新、更新哪里。这就是声明式 UI。
一句话总结: 命令式是你指挥细节,声明式是你描述结果。门槛更低,代码更少。
用一张图来对比两种模式的工作流程:
flowchart LR
subgraph 命令式_Imperative
A[XML 定义布局] --> B[findViewById 找控件]
B --> C[setText/setOnClickListener 手动更新]
end
subgraph 声明式_Declarative
D[Composable 函数描述界面] --> E[状态变化自动触发重组]
end
命令式_Imperative -.->|vs| 声明式_Declarative
左边命令式:你要自己找到控件、自己更新。右边声明式:你说长什么样,框架管更新。
1.2 Compose 的优势
- 更少的代码:一个 Text 控件从定义到展示,只需要一行代码
- 直观的状态管理:状态变化自动触发界面重组(Recompose),无需手动更新
- 强大的可组合性:小而独立的 Composable 函数自由组合
- 完全用 Kotlin 编写:可以使用 Kotlin 的所有语言特性(高阶函数、协程等)
- 与现有 View 体系互通:可以在 Compose 中嵌入 View,也可以在 View 中嵌入 Compose
二、环境搭建
2.1 Android Studio 版本
Jetpack Compose 入门系列(一):从零搭建到基础控件使用
一、前言
一直用 XML + View 写界面?Jetpack Compose 是你该学的新方向。
1.1 什么是 Compose?
Jetpack Compose 是 Google 在 2021 年正式推出的 Android 原生声明式 UI 框架——它不依赖 XML,而是用 Kotlin 代码直接"描述"界面长什么样。
来做个对比你就明白了。以前用 XML + View 体系写界面,大致是三步走:
// 第一步:在 XML 里定义好布局
// 第二步:在 Activity 里 findViewById 找到控件
// 第三步:调用 setText()、setOnClickListener() 手动更新
这套模式叫命令式 UI——你得像下指令一样告诉程序每一步该做什么。而 Compose 的做法完全不同:
// 你只需要描述:"这里有一个文本,内容是 Hello"
Text(text = "Hello")
你说"界面应该长这样",框架自己判断什么时候该更新、更新哪里。这就是声明式 UI。
一句话总结: 命令式是你指挥细节,声明式是你描述结果。门槛更低,代码更少。
用一张图来对比两种模式的工作流程:
flowchart LR
subgraph 命令式_Imperative
A[XML 定义布局] --> B[findViewById 找控件]
B --> C[setText/setOnClickListener 手动更新]
end
subgraph 声明式_Declarative
D[Composable 函数描述界面] --> E[状态变化自动触发重组]
end
命令式_Imperative -.->|vs| 声明式_Declarative
左边命令式:你要自己找到控件、自己更新。右边声明式:你说长什么样,框架管更新。
1.2 Compose 的优势
- 更少的代码:一个 Text 控件从定义到展示,只需要一行代码
- 直观的状态管理:状态变化自动触发界面重组(Recompose),无需手动更新
- 强大的可组合性:小而独立的 Composable 函数自由组合
- 完全用 Kotlin 编写:可以使用 Kotlin 的所有语言特性(高阶函数、协程等)
- 与现有 View 体系互通:可以在 Compose 中嵌入 View,也可以在 View 中嵌入 Compose
二、环境搭建
2.1 Android Studio 版本
Compose 需要 Android Studio Arctic Fox(2020.3.1)或更高版本。建议直接使用最新的稳定版 Android Studio, 本文示例代码使用的Android Studio版本是 2025.3.4 Patch 1。
2.2 创建支持 Compose 的项目
如果你从模板创建项目,Android Studio 提供了 "Empty Activity" 模板,勾选后会自动配置好所有依赖。
如果是已有项目要接入 Compose,需要手动配置以下内容。
2.3 Gradle 配置
第一步:设置 Kotlin 和 Compose 编译器
在项目根目录的 build.gradle.kts中:
// build.gradle.kts(项目级)
plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.kotlin.compose) apply false
}
第二步:声明依赖和指定版本
在 gradle/libs.versions.toml 声明依赖和指定版本:
// libs.versions.toml
[versions]
agp = "9.2.1"
coreKtx = "1.10.1"
lifecycleRuntimeKtx = "2.6.1"
activityCompose = "1.8.0"
kotlin = "2.2.10"
composeBom = "2026.02.01"
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" }
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" }
androidx-compose-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
第三步:添加 Compose BOM 和依赖
在模块的 build.gradle.kts 中:
// build.gradle.kts(模块级)
android {
// 需要启用 Compose
buildFeatures {
compose = true
}
}
dependencies {
// BOM(Bill of Materials):统一管理 Compose 版本,避免版本冲突
implementation(platform(libs.androidx.compose.bom))
// UI 基础
implementation(libs.androidx.compose.ui)
// UI 图形工具
implementation(libs.androidx.compose.ui.graphics)
// UI 预览(只在 debug 模式下需要)
implementation(libs.androidx.compose.ui.tooling.preview)
// Material 3 设计系统
implementation(libs.androidx.compose.material3)
// Activity Compose(setContent 扩展)
implementation(libs.androidx.activity.compose)
// 调试工具
debugImplementation(libs.androidx.compose.ui.tooling)
}
注意:
kotlinCompilerExtensionVersion必须与 Kotlin 版本匹配,具体对应关系可以查看 Compose 与 Kotlin 版本兼容表。
BOM 是什么? BOM(Bill of Materials)是一份"材料清单",你在 dependencies 中声明 Compose 库时不用写具体版本号,BOM 会自动为你选择兼容的版本。这样既不用记版本号,也不用担心版本冲突。
三、第一个 Compose 程序
3.1 Hello World
创建一个最简单的 Compose Activity:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// setContent 是 Activity 的扩展函数,用于设置 Compose 界面
setContent {
// 这里写 Compose 代码
Text(text = "Hello Compose!")
}
}
}
就这么简单。setContent 是 activity-compose 提供的扩展函数,它接受一个 @Composable 函数作为参数——所有 Compose 代码都在这里编写。
整个调用链的关系可以这样理解:
flowchart TB
A[Activity.onCreate] --> B[setContent 扩展函数]
B --> C[Composable 作用域建立]
C --> D[Text<br/>Hello Compose!]
style A fill:#e1f5fe
style B fill:#fff3e0
style C fill:#e8f5e9
style D fill:#fce4ec
3.2 Composable 函数
Text 是一个Composable 函数。任何被 @Composable 注解标记的函数都称为 Composable 函数:
@Composable
fun Greeting(name: String) {
Text(text = "Hello, $name!")
}
Composable 函数有两个硬性规则,刚接触时特别容易忽略:
- 函数名必须以大写字母开头。 这不是什么玄学——Compose 利用这个约定来区分"这是一个 Composable 界面组件"和"这是一个普通工具函数"。如果你用小写开头,编译器不会报错,但团队约定和 IDE 提示都会默认按大写走
- 只能在另一个 Composable 函数的作用域中调用 Composable 函数。 简单说,
setContent { }的花括号里、或者在某个@Composable fun xxx()里,才能调用别的 Composable。在普通 Kotlin 函数里直接调用Text()会编译报错
所以上面的 Activity 可以改写成:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Greeting(name = "Compose")
}
}
}
@Composable
fun Greeting(name: String) {
Text(text = "Hello, $name!")
}
3.3 主题和预览
为了让界面更好看且贴近 Material Design,通常会用 MaterialTheme 包裹:
setContent {
MaterialTheme {
Greeting(name = "Compose")
}
}
另外,Compose 提供了预览功能——用 @Preview 注解标注一个 Composable 函数,就可以在 Android Studio 的 Design 面板中实时看到效果,无需运行到真机:
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
MaterialTheme {
Greeting(name = "Compose")
}
}
@Preview只能标注不接收参数或参数有默认值的 Composable 函数,因为预览时无法传入参数。
四、基础控件详解
接下来逐个介绍最常用的 Compose 控件。每种控件我都会给出主要参数说明和完整的示例代码。
4.1 Text:文本显示
Text 是最基础的控件,用来显示文字:
@Composable
fun TextExample() {
Text(
text = "Hello Compose",
color = Color.Red,
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
textAlign = TextAlign.Center,
maxLines = 2,
overflow = TextOverflow.Ellipsis
)
}
常用参数:
| 参数 | 类型 | 说明 |
|---|---|---|
text | String / AnnotatedString | 要显示的文本 |
color | Color | 文字颜色 |
fontSize | TextUnit(sp) | 字体大小,用 .sp 单位 |
fontWeight | FontWeight | 字重(Bold、Light、Normal 等) |
textAlign | TextAlign | 对齐方式(Start、Center、End 等) |
maxLines | Int | 最大行数 |
overflow | TextOverflow | 超出时的处理方式(Ellipsis 省略号、Clip 裁剪) |
style | TextStyle | 统一样式设置,包含上述所有属性 |
单位说明:Compose 中使用
.dp(独立密度像素)表示尺寸,.sp(缩放独立像素)表示字体大小,这和 XML 中的 dp/sp 含义一致。
以上全部参数只是 Text 的一部分,更多参数可以在 IDE 中按 Ctrl+P(Windows)或 Command+P(Mac)查看。
4.2 Button:按钮
Button 是 Material 3 的按钮组件:
@Composable
fun ButtonExample() {
Button(
onClick = { /* 点击回调 */ },
enabled = true,
colors = ButtonDefaults.buttonColors(
containerColor = Color.Blue,
contentColor = Color.White
)
) {
// Button 的内容区域,可以放任何 Composable
Text(text = "点击我")
}
}
关键点:
Button的content参数(花括号内的内容)可以是 任意 Composable,不一定是 Text。你可以放 Image、Icon、Row 等onClick是必须传入的参数,定义了点击事件enabled控制按钮是否可点击
其他按钮变体:
// 描边按钮
OutlinedButton(onClick = { }) {
Text("Outlined Button")
}
// 文字按钮
TextButton(onClick = { }) {
Text("Text Button")
}
// 带图标的按钮
Button(onClick = { }) {
Icon(Icons.Default.Add, contentDescription = "添加")
Spacer(modifier = Modifier.width(8.dp))
Text("添加")
}
4.3 TextField:文本输入框
文本输入框用来接收用户输入:
@Composable
fun TextFieldExample() {
// 定义一个可变状态来存储输入内容
var input by remember { mutableStateOf("") }
OutlinedTextField(
value = input,
onValueChange = { input = it },
label = { Text("用户名") },
placeholder = { Text("请输入用户名") },
singleLine = true,
isError = input.length > 10,
supportingText = {
if (input.length > 10) {
Text("用户名不能超过10个字符", color = MaterialTheme.colorScheme.error)
}
}
)
}
关键概念——State(状态):
你可能注意到了 remember 和 mutableStateOf——这是 Compose 中管理状态的机制。简单来说:
mutableStateOf("")创建了一个可观察的状态remember保证这个状态在重组(界面刷新)时不被重置onValueChange在每次输入变化时回调,我们把新值更新到状态中
关于 State 的详细讲解在第二篇文章中,这里先记住用法即可。
常用参数:
| 参数 | 说明 |
|---|---|
value | 当前输入框的内容 |
onValueChange | 内容变化时的回调 |
label | 标签(显示在输入框上方或内部) |
placeholder | 占位提示文字 |
singleLine | 是否单行输入 |
isError | 是否显示错误状态 |
keyboardOptions | 键盘配置(数字键盘、邮箱键盘等) |
visualTransformation | 视觉变换(如密码遮罩 PasswordVisualTransformation) |
密码输入框示例:
@Composable
fun PasswordField() {
var password by remember { mutableStateOf("") }
OutlinedTextField(
value = password,
onValueChange = { password = it },
label = { Text("密码") },
visualTransformation = PasswordVisualTransformation(),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password)
)
}
4.4 Image:图片显示
Image 用来显示图片资源:
@Composable
fun ImageExample() {
Image(
painter = painterResource(id = R.drawable.my_image),
contentDescription = "图片描述",
modifier = Modifier.size(200.dp),
contentScale = ContentScale.Crop
)
}
常用参数:
| 参数 | 说明 |
|---|---|
painter | 图片绘制器,painterResource() 加载本地图片 |
contentDescription | 无障碍描述,纯装饰性图片可传 null |
contentScale | 图片缩放模式(Crop 裁剪、Fit 适应、Fill 填充等) |
alpha | 透明度(0f ~ 1f) |
常用 ContentScale 模式:
ContentScale.Crop // 裁剪居中(类似 XML 的 centerCrop)
ContentScale.Fit // 等比缩放,可能留白(类似 fitCenter)
ContentScale.FillBounds // 拉伸填充(类似 fitXY)
ContentScale.Inside // 缩小到容器内,不放大
painterResource()会自动适配不同密度的图片资源,加载方式与 XML 中的R.drawable.xxx一致。 如果是从网络加载图片,需要使用Coil等三方库的AsyncImage,这是后话。
4.5 Spacer:占位间距
Spacer 用来在布局中插入空白区域:
Spacer(modifier = Modifier.height(16.dp)) // 垂直间距
Spacer(modifier = Modifier.width(8.dp)) // 水平间距
五、Modifier 详解
Modifier 是 Compose 中最核心的概念之一。它用来装饰或增强一个 Composable 的外观和交互行为。
5.1 使用方式
几乎所有 Composable 都接收一个可选的 modifier 参数:
Text(
text = "Hello",
modifier = Modifier
.padding(16.dp) // 设置内边距
.background(Color.Yellow) // 设置背景色
.clickable { /* 点击 */ } // 设置点击
.fillMaxWidth() // 填充最大宽度
)
5.2 链式调用与顺序
Modifier 通过链式调用组合多个行为,而且顺序很重要:
// 顺序一:先 padding 再 background
@Composable
fun ModifierOrder1() {
Text(
text = "Hello",
modifier = Modifier
.padding(16.dp) // 先给文字周围留 16dp 空白
.background(Color.Red) // 再给整个区域(含 padding)上红色背景
)
}
// 顺序二:先 background 再 padding
@Composable
fun ModifierOrder2() {
Text(
text = "Hello",
modifier = Modifier
.background(Color.Red) // 先给文字本身加上红色背景
.padding(16.dp) // 再在红色背景周围留白
)
}
两种顺序的效果完全不同。用下面的图来看更直观:
flowchart LR
subgraph 顺序一_padding_then_background
A1[Text 文字] --> A2[padding 16dp 扩大区域]
A2 --> A3[background Red 给整个区域上色]
end
subgraph 顺序二_background_then_padding
B1[Text 文字] --> B2[background Red 仅文字区域上色]
B2 --> B3[padding 16dp 在红色区域外留白]
end
- 顺序一:padding 区域也会被染成红色(padding 在 background 内部)
- 顺序二:padding 区域是透明的(padding 在 background 外部)
记住原则: Modifier 的执行顺序是从左到右的,每个 Modifier 会包裹前一个 Modifier 的结果。
5.3 常用 Modifier 速查
| Modifier | 作用 |
|---|---|
.padding(all = 16.dp) | 内边距 |
.padding(start = 8.dp, top = 16.dp) | 指定方向的内边距 |
.size(48.dp) | 宽高设为固定值 |
.width(100.dp) | 宽度固定 |
.height(100.dp) | 高度固定 |
.fillMaxWidth() | 撑满父容器宽度 |
.fillMaxHeight() | 撑满父容器高度 |
.fillMaxSize() | 撑满父容器 |
.background(Color.Blue) | 背景色 |
.background(Color.Blue, shape = RoundedCornerShape(8.dp)) | 圆角背景 |
.clickable { } | 点击事件 |
.border(width = 1.dp, color = Color.Gray) | 边框 |
.border(width = 1.dp, color = Color.Gray, shape = RoundedCornerShape(8.dp)) | 圆角边框 |
.clip(RoundedCornerShape(8.dp)) | 裁剪为圆角 |
.offset(x = 10.dp, y = 10.dp) | 偏移位置 |
.alpha(0.5f) | 透明度 |
.rotate(45f) | 旋转角度 |
.weight(1f) | 在 Row/Column 中分配权重(类似 LinearLayout 的 weight) |
六、实战:一个简单登录界面
把上面的知识串起来,写一个完整的登录界面:
@Composable
fun LoginScreen() {
// 状态
var username by remember { mutableStateOf("") }
var password by remember { mutableStateOf("") }
// Column 是垂直布局容器,相当于 LinearLayout(vertical)
Column(
modifier = Modifier
.fillMaxSize()
.padding(24.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
// 标题
Text(
text = "欢迎登录",
fontSize = 28.sp,
fontWeight = FontWeight.Bold,
color = MaterialTheme.colorScheme.primary
)
Spacer(modifier = Modifier.height(32.dp))
// 用户名输入框
OutlinedTextField(
value = username,
onValueChange = { username = it },
label = { Text("用户名") },
singleLine = true,
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(16.dp))
// 密码输入框
OutlinedTextField(
value = password,
onValueChange = { password = it },
label = { Text("密码") },
singleLine = true,
visualTransformation = PasswordVisualTransformation(),
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(24.dp))
// 登录按钮
Button(
onClick = { /* 执行登录 */ },
modifier = Modifier
.fillMaxWidth()
.height(50.dp),
enabled = username.isNotBlank() && password.isNotBlank()
) {
Text(text = "登录", fontSize = 18.sp)
}
}
}
把这个 Composable 放到 Activity 的 setContent 中:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MaterialTheme {
LoginScreen()
}
}
}
}
效果说明:居中显示的"欢迎登录"标题,两个输入框,底部一个登录按钮。用户名或密码为空时按钮为禁用状态。
整个登录界面的组件树结构如下:
flowchart TB
A[LoginScreen] --> B[Column<br/>垂直居中]
B --> C[Text<br/>欢迎登录]
B --> D[Spacer 32dp]
B --> E[OutlinedTextField<br/>用户名]
B --> F[Spacer 16dp]
B --> G[OutlinedTextField<br/>密码]
B --> H[Spacer 24dp]
B --> I[Button<br/>登录<br/>enabled 受状态控制]
七、注意事项与小技巧
7.1 避免在 Composable 函数中写耗时操作
// ❌ 错误:在 Composable 中直接执行耗时操作
@Composable
fun BadExample() {
val result = someHeavyComputation() // Compose 可能频繁重组,导致卡顿
Text(text = result)
}
// ✅ 正确:使用 LaunchedEffect 或回调
@Composable
fun GoodExample() {
var result by remember { mutableStateOf("") }
LaunchedEffect(Unit) {
result = someHeavyComputation() // 在协程中执行
}
Text(text = result)
}
7.2 Modifier 参数尽量暴露出去
// ✅ 好的实践:将 modifier 作为参数并提供默认值
@Composable
fun MyCustomButton(
text: String,
onClick: () -> Unit,
modifier: Modifier = Modifier
) {
Button(
onClick = onClick,
modifier = modifier
) {
Text(text = text)
}
}
这样调用方可以自由定制按钮的样式和行为。
7.3 资源引用
在 Compose 中获取颜色、字符串、尺寸等资源:
// 字符串资源
val appName = stringResource(id = R.string.app_name)
// 颜色资源(如果使用了 Material3 的话推荐直接用 MaterialTheme)
val customColor = colorResource(id = R.color.custom_color)
// 尺寸资源
val dimen = dimensionResource(id = R.dimen.custom_dimen)
八、总结
这篇文章我们学习了:
- Compose 的核心概念:声明式 UI 与命令式 UI 的区别
- 环境搭建:Gradle 配置、BOM 的使用
- Composable 函数:基本规范和注意事项
- 基础控件:Text、Button、OutlinedTextField、Image、Spacer
- Modifier:链式调用、执行顺序、常用 Modifier 速查
- 实战:一个完整的登录界面
这些知识足以让你写出简单的 Compose 页面了。下一篇文章我们将进一步探讨 布局系统(Column、Row、Box、LazyColumn 等)和 State 管理(remember、状态提升、StateFlow 收集),这些是写出复杂交互界面的基础。
如果你在搭建过程中遇到任何问题,欢迎在评论区留言交流。**** Compose 需要 Android Studio Arctic Fox(2020.3.1)或更高版本。建议直接使用最新的稳定版 Android Studio, 文章使用的Android Studio版本是 2025.3.4 Patch 1。
2.2 创建支持 Compose 的项目
如果你从模板创建项目,Android Studio 提供了 "Empty Activity" 模板,勾选后会自动配置好所有依赖。
如果是已有项目要接入 Compose,需要手动配置以下内容。
2.3 Gradle 配置
第一步:设置 Kotlin 和 Compose 编译器
在项目根目录的 build.gradle.kts中:
// build.gradle.kts(项目级)
plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.kotlin.compose) apply false
}
第二步:声明依赖和指定版本
在 gradle/libs.versions.toml 声明依赖和指定版本:
// gradle/libs.versions.toml
[versions]
agp = "9.2.1"
coreKtx = "1.10.1"
lifecycleRuntimeKtx = "2.6.1"
activityCompose = "1.8.0"
kotlin = "2.2.10"
composeBom = "2026.02.01"
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" }
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" }
androidx-compose-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
第三步:添加 Compose BOM 和依赖
在模块的 build.gradle.kts 中:
// build.gradle.kts(模块级)
android {
// 需要启用 Compose
buildFeatures {
compose = true
}
}
dependencies {
// BOM(Bill of Materials):统一管理 Compose 版本,避免版本冲突
implementation(platform(libs.androidx.compose.bom))
// UI 基础
implementation(libs.androidx.compose.ui)
// UI 图形工具
implementation(libs.androidx.compose.ui.graphics)
// UI 预览(只在 debug 模式下需要)
implementation(libs.androidx.compose.ui.tooling.preview)
// Material 3 设计系统
implementation(libs.androidx.compose.material3)
// Activity Compose(setContent 扩展)
implementation(libs.androidx.activity.compose)
// 调试工具
debugImplementation(libs.androidx.compose.ui.tooling)
}
注意:
kotlinCompilerExtensionVersion必须与 Kotlin 版本匹配,具体对应关系可以查看 Compose 与 Kotlin 版本兼容表。
BOM 是什么? BOM(Bill of Materials)是一份"材料清单",你在 dependencies 中声明 Compose 库时不用写具体版本号,BOM 会自动为你选择兼容的版本。这样既不用记版本号,也不用担心版本冲突。
三、第一个 Compose 程序
3.1 Hello World
创建一个最简单的 Compose Activity:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// setContent 是 Activity 的扩展函数,用于设置 Compose 界面
setContent {
// 这里写 Compose 代码
Text(text = "Hello Compose!")
}
}
}
就这么简单。setContent 是 activity-compose 提供的扩展函数,它接受一个 @Composable 函数作为参数——所有 Compose 代码都在这里编写。
整个调用链的关系可以这样理解:
flowchart TB
A[Activity.onCreate] --> B[setContent 扩展函数]
B --> C[Composable 作用域建立]
C --> D[Text<br/>Hello Compose!]
style A fill:#e1f5fe
style B fill:#fff3e0
style C fill:#e8f5e9
style D fill:#fce4ec
3.2 Composable 函数
Text 是一个Composable 函数。任何被 @Composable 注解标记的函数都称为 Composable 函数:
@Composable
fun Greeting(name: String) {
Text(text = "Hello, $name!")
}
Composable 函数有两个硬性规则,刚接触时特别容易忽略:
- 函数名必须以大写字母开头。 这不是什么玄学——Compose 利用这个约定来区分"这是一个 Composable 界面组件"和"这是一个普通工具函数"。如果你用小写开头,编译器不会报错,但团队约定和 IDE 提示都会默认按大写走
- 只能在另一个 Composable 函数的作用域中调用 Composable 函数。 简单说,
setContent { }的花括号里、或者在某个@Composable fun xxx()里,才能调用别的 Composable。在普通 Kotlin 函数里直接调用Text()会编译报错
所以上面的 Activity 可以改写成:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Greeting(name = "Compose")
}
}
}
@Composable
fun Greeting(name: String) {
Text(text = "Hello, $name!")
}
3.3 主题和预览
为了让界面更好看且贴近 Material Design,通常会用 MaterialTheme 包裹:
setContent {
MaterialTheme {
Greeting(name = "Compose")
}
}
另外,Compose 提供了预览功能——用 @Preview 注解标注一个 Composable 函数,就可以在 Android Studio 的 Design 面板中实时看到效果,无需运行到真机:
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
MaterialTheme {
Greeting(name = "Compose")
}
}
@Preview只能标注不接收参数或参数有默认值的 Composable 函数,因为预览时无法传入参数。
四、基础控件详解
接下来逐个介绍最常用的 Compose 控件。每种控件我都会给出主要参数说明和完整的示例代码。
4.1 Text:文本显示
Text 是最基础的控件,用来显示文字:
@Composable
fun TextExample() {
Text(
text = "Hello Compose",
color = Color.Red,
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
textAlign = TextAlign.Center,
maxLines = 2,
overflow = TextOverflow.Ellipsis
)
}
常用参数:
| 参数 | 类型 | 说明 |
|---|---|---|
text | String / AnnotatedString | 要显示的文本 |
color | Color | 文字颜色 |
fontSize | TextUnit(sp) | 字体大小,用 .sp 单位 |
fontWeight | FontWeight | 字重(Bold、Light、Normal 等) |
textAlign | TextAlign | 对齐方式(Start、Center、End 等) |
maxLines | Int | 最大行数 |
overflow | TextOverflow | 超出时的处理方式(Ellipsis 省略号、Clip 裁剪) |
style | TextStyle | 统一样式设置,包含上述所有属性 |
单位说明:Compose 中使用
.dp(独立密度像素)表示尺寸,.sp(缩放独立像素)表示字体大小,这和 XML 中的 dp/sp 含义一致。
以上全部参数只是 Text 的一部分,更多参数可以在 IDE 中按 Ctrl+P(Windows)或 Command+P(Mac)查看。
4.2 Button:按钮
Button 是 Material 3 的按钮组件:
@Composable
fun ButtonExample() {
Button(
onClick = { /* 点击回调 */ },
enabled = true,
colors = ButtonDefaults.buttonColors(
containerColor = Color.Blue,
contentColor = Color.White
)
) {
// Button 的内容区域,可以放任何 Composable
Text(text = "点击我")
}
}
关键点:
Button的content参数(花括号内的内容)可以是 任意 Composable,不一定是 Text。你可以放 Image、Icon、Row 等onClick是必须传入的参数,定义了点击事件enabled控制按钮是否可点击
其他按钮变体:
// 描边按钮
OutlinedButton(onClick = { }) {
Text("Outlined Button")
}
// 文字按钮
TextButton(onClick = { }) {
Text("Text Button")
}
// 带图标的按钮
Button(onClick = { }) {
Icon(Icons.Default.Add, contentDescription = "添加")
Spacer(modifier = Modifier.width(8.dp))
Text("添加")
}
4.3 TextField:文本输入框
文本输入框用来接收用户输入:
@Composable
fun TextFieldExample() {
// 定义一个可变状态来存储输入内容
var input by remember { mutableStateOf("") }
OutlinedTextField(
value = input,
onValueChange = { input = it },
label = { Text("用户名") },
placeholder = { Text("请输入用户名") },
singleLine = true,
isError = input.length > 10,
supportingText = {
if (input.length > 10) {
Text("用户名不能超过10个字符", color = MaterialTheme.colorScheme.error)
}
}
)
}
关键概念——State(状态):
你可能注意到了 remember 和 mutableStateOf——这是 Compose 中管理状态的机制。简单来说:
mutableStateOf("")创建了一个可观察的状态remember保证这个状态在重组(界面刷新)时不被重置onValueChange在每次输入变化时回调,我们把新值更新到状态中
关于 State 的详细讲解在第二篇文章中,这里先记住用法即可。
常用参数:
| 参数 | 说明 |
|---|---|
value | 当前输入框的内容 |
onValueChange | 内容变化时的回调 |
label | 标签(显示在输入框上方或内部) |
placeholder | 占位提示文字 |
singleLine | 是否单行输入 |
isError | 是否显示错误状态 |
keyboardOptions | 键盘配置(数字键盘、邮箱键盘等) |
visualTransformation | 视觉变换(如密码遮罩 PasswordVisualTransformation) |
密码输入框示例:
@Composable
fun PasswordField() {
var password by remember { mutableStateOf("") }
OutlinedTextField(
value = password,
onValueChange = { password = it },
label = { Text("密码") },
visualTransformation = PasswordVisualTransformation(),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password)
)
}
4.4 Image:图片显示
Image 用来显示图片资源:
@Composable
fun ImageExample() {
Image(
painter = painterResource(id = R.drawable.my_image),
contentDescription = "图片描述",
modifier = Modifier.size(200.dp),
contentScale = ContentScale.Crop
)
}
常用参数:
| 参数 | 说明 |
|---|---|
painter | 图片绘制器,painterResource() 加载本地图片 |
contentDescription | 无障碍描述,纯装饰性图片可传 null |
contentScale | 图片缩放模式(Crop 裁剪、Fit 适应、Fill 填充等) |
alpha | 透明度(0f ~ 1f) |
常用 ContentScale 模式:
ContentScale.Crop // 裁剪居中(类似 XML 的 centerCrop)
ContentScale.Fit // 等比缩放,可能留白(类似 fitCenter)
ContentScale.FillBounds // 拉伸填充(类似 fitXY)
ContentScale.Inside // 缩小到容器内,不放大
painterResource()会自动适配不同密度的图片资源,加载方式与 XML 中的R.drawable.xxx一致。 如果是从网络加载图片,需要使用Coil等三方库的AsyncImage,这是后话。
4.5 Spacer:占位间距
Spacer 用来在布局中插入空白区域:
Spacer(modifier = Modifier.height(16.dp)) // 垂直间距
Spacer(modifier = Modifier.width(8.dp)) // 水平间距
五、Modifier 详解
Modifier 是 Compose 中最核心的概念之一。它用来装饰或增强一个 Composable 的外观和交互行为。
5.1 使用方式
几乎所有 Composable 都接收一个可选的 modifier 参数:
Text(
text = "Hello",
modifier = Modifier
.padding(16.dp) // 设置内边距
.background(Color.Yellow) // 设置背景色
.clickable { /* 点击 */ } // 设置点击
.fillMaxWidth() // 填充最大宽度
)
5.2 链式调用与顺序
Modifier 通过链式调用组合多个行为,而且顺序很重要:
// 顺序一:先 padding 再 background
@Composable
fun ModifierOrder1() {
Text(
text = "Hello",
modifier = Modifier
.padding(16.dp) // 先给文字周围留 16dp 空白
.background(Color.Red) // 再给整个区域(含 padding)上红色背景
)
}
// 顺序二:先 background 再 padding
@Composable
fun ModifierOrder2() {
Text(
text = "Hello",
modifier = Modifier
.background(Color.Red) // 先给文字本身加上红色背景
.padding(16.dp) // 再在红色背景周围留白
)
}
两种顺序的效果完全不同。用下面的图来看更直观:
flowchart LR
subgraph 顺序一_padding_then_background
A1[Text 文字] --> A2[padding 16dp 扩大区域]
A2 --> A3[background Red 给整个区域上色]
end
subgraph 顺序二_background_then_padding
B1[Text 文字] --> B2[background Red 仅文字区域上色]
B2 --> B3[padding 16dp 在红色区域外留白]
end
- 顺序一:padding 区域也会被染成红色(padding 在 background 内部)
- 顺序二:padding 区域是透明的(padding 在 background 外部)
记住原则: Modifier 的执行顺序是从左到右的,每个 Modifier 会包裹前一个 Modifier 的结果。
5.3 常用 Modifier 速查
| Modifier | 作用 |
|---|---|
.padding(all = 16.dp) | 内边距 |
.padding(start = 8.dp, top = 16.dp) | 指定方向的内边距 |
.size(48.dp) | 宽高设为固定值 |
.width(100.dp) | 宽度固定 |
.height(100.dp) | 高度固定 |
.fillMaxWidth() | 撑满父容器宽度 |
.fillMaxHeight() | 撑满父容器高度 |
.fillMaxSize() | 撑满父容器 |
.background(Color.Blue) | 背景色 |
.background(Color.Blue, shape = RoundedCornerShape(8.dp)) | 圆角背景 |
.clickable { } | 点击事件 |
.border(width = 1.dp, color = Color.Gray) | 边框 |
.border(width = 1.dp, color = Color.Gray, shape = RoundedCornerShape(8.dp)) | 圆角边框 |
.clip(RoundedCornerShape(8.dp)) | 裁剪为圆角 |
.offset(x = 10.dp, y = 10.dp) | 偏移位置 |
.alpha(0.5f) | 透明度 |
.rotate(45f) | 旋转角度 |
.weight(1f) | 在 Row/Column 中分配权重(类似 LinearLayout 的 weight) |
六、实战:一个简单登录界面
把上面的知识串起来,写一个完整的登录界面:
@Composable
fun LoginScreen() {
// 状态
var username by remember { mutableStateOf("") }
var password by remember { mutableStateOf("") }
// Column 是垂直布局容器,相当于 LinearLayout(vertical)
Column(
modifier = Modifier
.fillMaxSize()
.padding(24.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
// 标题
Text(
text = "欢迎登录",
fontSize = 28.sp,
fontWeight = FontWeight.Bold,
color = MaterialTheme.colorScheme.primary
)
Spacer(modifier = Modifier.height(32.dp))
// 用户名输入框
OutlinedTextField(
value = username,
onValueChange = { username = it },
label = { Text("用户名") },
singleLine = true,
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(16.dp))
// 密码输入框
OutlinedTextField(
value = password,
onValueChange = { password = it },
label = { Text("密码") },
singleLine = true,
visualTransformation = PasswordVisualTransformation(),
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(24.dp))
// 登录按钮
Button(
onClick = { /* 执行登录 */ },
modifier = Modifier
.fillMaxWidth()
.height(50.dp),
enabled = username.isNotBlank() && password.isNotBlank()
) {
Text(text = "登录", fontSize = 18.sp)
}
}
}
把这个 Composable 放到 Activity 的 setContent 中:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MaterialTheme {
LoginScreen()
}
}
}
}
效果说明:居中显示的"欢迎登录"标题,两个输入框,底部一个登录按钮。用户名或密码为空时按钮为禁用状态。
整个登录界面的组件树结构如下:
flowchart TB
A[LoginScreen] --> B[Column<br/>垂直居中]
B --> C[Text<br/>欢迎登录]
B --> D[Spacer 32dp]
B --> E[OutlinedTextField<br/>用户名]
B --> F[Spacer 16dp]
B --> G[OutlinedTextField<br/>密码]
B --> H[Spacer 24dp]
B --> I[Button<br/>登录<br/>enabled 受状态控制]
七、注意事项与小技巧
7.1 避免在 Composable 函数中写耗时操作
// ❌ 错误:在 Composable 中直接执行耗时操作
@Composable
fun BadExample() {
val result = someHeavyComputation() // Compose 可能频繁重组,导致卡顿
Text(text = result)
}
// ✅ 正确:使用 LaunchedEffect 或回调
@Composable
fun GoodExample() {
var result by remember { mutableStateOf("") }
LaunchedEffect(Unit) {
result = someHeavyComputation() // 在协程中执行
}
Text(text = result)
}
7.2 Modifier 参数尽量暴露出去
// ✅ 好的实践:将 modifier 作为参数并提供默认值
@Composable
fun MyCustomButton(
text: String,
onClick: () -> Unit,
modifier: Modifier = Modifier
) {
Button(
onClick = onClick,
modifier = modifier
) {
Text(text = text)
}
}
这样调用方可以自由定制按钮的样式和行为。
7.3 资源引用
在 Compose 中获取颜色、字符串、尺寸等资源:
// 字符串资源
val appName = stringResource(id = R.string.app_name)
// 颜色资源(如果使用了 Material3 的话推荐直接用 MaterialTheme)
val customColor = colorResource(id = R.color.custom_color)
// 尺寸资源
val dimen = dimensionResource(id = R.dimen.custom_dimen)
八、总结
这篇文章我们学习了:
- Compose 的核心概念:声明式 UI 与命令式 UI 的区别
- 环境搭建:Gradle 配置、BOM 的使用
- Composable 函数:基本规范和注意事项
- 基础控件:Text、Button、OutlinedTextField、Image、Spacer
- Modifier:链式调用、执行顺序、常用 Modifier 速查
- 实战:一个完整的登录界面
这些知识足以让你写出简单的 Compose 页面了。下一篇文章我们将进一步探讨 布局系统(Column、Row、Box、LazyColumn 等)和 State 管理(remember、状态提升、StateFlow 收集),这些是写出复杂交互界面的基础。
如果你在搭建过程中遇到任何问题,欢迎在评论区留言交流。
一、前言
如果你有 Android 开发经验,但一直在使用 XML + View 体系编写界面,那么 Jetpack Compose 是一个值得你投入时间去学习的现代 UI 工具包。
1.1 什么是 Compose?
Jetpack Compose 是 Google 在 2021 年正式推出的 Android 原生 UI 工具包——它不依赖 XML,而是用 Kotlin 代码直接"描述"界面长什么样。
来做个对比你就明白了。以前用 XML + View 体系写界面,大致是三步走:
// 第一步:在 XML 里定义好布局
// 第二步:在 Activity 里 findViewById 找到控件
// 第三步:调用 setText()、setOnClickListener() 手动更新
这套模式叫命令式 UI——你得像下指令一样告诉程序每一步该做什么。而 Compose 的做法完全不同:
// 你只需要描述:"这里有一个文本,内容是 Hello"
Text(text = "Hello")
你说"界面应该长这样",框架自己判断什么时候该更新、更新哪里。这就是声明式 UI。
一句话总结: 命令式是你指挥细节,声明式是你描述结果。门槛更低,代码更少。
用一张图来对比两种模式的工作流程:
flowchart LR
subgraph 命令式_Imperative
A[XML 定义布局] --> B[findViewById 找控件]
B --> C[setText/setOnClickListener 手动更新]
end
subgraph 声明式_Declarative
D[Composable 函数描述界面] --> E[状态变化自动触发重组]
end
命令式_Imperative -.->|vs| 声明式_Declarative
左边命令式:你要自己找到控件、自己更新。右边声明式:你说长什么样,框架管更新。
1.2 Compose 的优势
- 更少的代码:一个 Text 控件从定义到展示,只需要一行代码
- 直观的状态管理:状态变化自动触发界面重组(Recompose),无需手动更新
- 强大的可组合性:小而独立的 Composable 函数自由组合
- 完全用 Kotlin 编写:可以使用 Kotlin 的所有语言特性(高阶函数、协程等)
- 与现有 View 体系互通:可以在 Compose 中嵌入 View,也可以在 View 中嵌入 Compose
二、环境搭建
2.1 Android Studio 版本
Compose 需要 Android Studio Arctic Fox(2020.3.1)或更高版本。建议直接使用最新的稳定版 Android Studio。
2.2 创建支持 Compose 的项目
如果你从模板创建项目,Android Studio 提供了 "Empty Compose Activity" 模板,勾选后会自动配置好所有依赖。
如果是已有项目要接入 Compose,需要手动配置以下内容。
2.3 Gradle 配置
第一步:设置 Kotlin 版本和 Compose 编译器插件
在项目根目录的 build.gradle.kts(或 build.gradle)中:
// build.gradle.kts(项目级)
plugins {
id("com.android.application") version "8.7.0" apply false
id("org.jetbrains.kotlin.android") version "2.3.20" apply false
id("org.jetbrains.kotlin.plugin.compose") version "2.3.20" apply false
}
注意:从 Kotlin 2.0 开始,Compose 编译器以独立的 Gradle 插件
org.jetbrains.kotlin.plugin.compose形式提供,不再需要旧版的kotlinCompilerExtensionVersion配置方式。插件版本号与 Kotlin 版本保持一致。
第二步:添加 Compose BOM 和依赖
在模块的 build.gradle.kts 中:
// build.gradle.kts(模块级)
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("org.jetbrains.kotlin.plugin.compose") // Kotlin 2.0+ 新增的 Compose 编译器插件
}
android {
buildFeatures {
compose = true
}
}
dependencies {
// BOM(Bill of Materials):统一管理 Compose 版本,避免版本冲突
val composeBom = platform("androidx.compose:compose-bom:2026.05.00")
implementation(composeBom)
// UI 基础
implementation("androidx.compose.ui:ui")
// UI 图形工具
implementation("androidx.compose.ui:ui-graphics")
// UI 预览(只在 debug 模式下需要)
implementation("androidx.compose.ui:ui-tooling-preview")
// Material 3 设计系统
implementation("androidx.compose.material3:material3")
// Activity Compose(setContent 扩展)
implementation("androidx.activity:activity-compose:1.13.0")
// 调试工具
debugImplementation("androidx.compose.ui:ui-tooling")
}
注意:Kotlin 2.0+ 使用
org.jetbrains.kotlin.plugin.compose插件替代了旧的composeOptions { kotlinCompilerExtensionVersion = "..." }配置方式。插件版本与 Kotlin 版本保持一致,无需手动管理编译器版本对应关系。兼容映射可参考 Compose 与 Kotlin 版本兼容表。
BOM 是什么? BOM(Bill of Materials)是一份"材料清单",你在 dependencies 中声明 Compose 库时不用写具体版本号,BOM 会自动为你选择兼容的版本。这样既不用记版本号,也不用担心版本冲突。
三、第一个 Compose 程序
3.1 Hello World
创建一个最简单的 Compose Activity:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// setContent 是 Activity 的扩展函数,用于设置 Compose 界面
setContent {
// 这里写 Compose 代码
Text(text = "Hello Compose!")
}
}
}
就这么简单。setContent 是 activity-compose 提供的扩展函数,它接受一个 @Composable 函数作为参数——所有 Compose 代码都在这里编写。
整个调用链的关系可以这样理解:
flowchart TB
A[Activity.onCreate] --> B[setContent 扩展函数]
B --> C[Composable 作用域建立]
C --> D[Text<br/>Hello Compose!]
style A fill:#e1f5fe
style B fill:#fff3e0
style C fill:#e8f5e9
style D fill:#fce4ec
3.2 Composable 函数
Text 是一个Composable 函数。任何被 @Composable 注解标记的函数都称为 Composable 函数:
@Composable
fun Greeting(name: String) {
Text(text = "Hello, $name!")
}
Composable 函数有两个硬性规则,刚接触时特别容易忽略:
- 函数名必须以大写字母开头。 这不是什么玄学——Compose 利用这个约定来区分"这是一个 Composable 界面组件"和"这是一个普通工具函数"。如果你用小写开头,编译器不会报错,但团队约定和 IDE 提示都会默认按大写走
- 只能在另一个 Composable 函数的作用域中调用 Composable 函数。 简单说,
setContent { }的花括号里、或者在某个@Composable fun xxx()里,才能调用别的 Composable。在普通 Kotlin 函数里直接调用Text()会编译报错
所以上面的 Activity 可以改写成:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Greeting(name = "Compose")
}
}
}
@Composable
fun Greeting(name: String) {
Text(text = "Hello, $name!")
}
3.3 主题和预览
为了让界面更好看且贴近 Material Design,通常会用 MaterialTheme 包裹:
setContent {
MaterialTheme {
Greeting(name = "Compose")
}
}
另外,Compose 提供了预览功能——用 @Preview 注解标注一个 Composable 函数,就可以在 Android Studio 的 Design 面板中实时看到效果,无需运行到真机:
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
MaterialTheme {
Greeting(name = "Compose")
}
}
@Preview只能标注不接收参数或参数有默认值的 Composable 函数,因为预览时无法传入参数。
四、基础控件详解
接下来逐个介绍最常用的 Compose 控件。每种控件我都会给出主要参数说明和完整的示例代码。
4.1 Text:文本显示
Text 是最基础的控件,用来显示文字:
@Composable
fun TextExample() {
Text(
text = "Hello Compose",
color = Color.Red,
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
textAlign = TextAlign.Center,
maxLines = 2,
overflow = TextOverflow.Ellipsis
)
}
常用参数:
| 参数 | 类型 | 说明 |
|---|---|---|
text | String / AnnotatedString | 要显示的文本 |
color | Color | 文字颜色 |
fontSize | TextUnit(sp) | 字体大小,用 .sp 单位 |
fontWeight | FontWeight | 字重(Bold、Light、Normal 等) |
textAlign | TextAlign | 对齐方式(Start、Center、End 等) |
maxLines | Int | 最大行数 |
overflow | TextOverflow | 超出时的处理方式(Ellipsis 省略号、Clip 裁剪) |
style | TextStyle | 统一样式设置,包含上述所有属性 |
单位说明:Compose 中使用
.dp(独立密度像素)表示尺寸,.sp(缩放独立像素)表示字体大小,这和 XML 中的 dp/sp 含义一致。
以上全部参数只是 Text 的一部分,更多参数可以在 IDE 中按 Ctrl+P(Windows)或 Command+P(Mac)查看。
4.2 Button:按钮
Button 是 Material 3 的按钮组件:
@Composable
fun ButtonExample() {
Button(
onClick = { /* 点击回调 */ },
enabled = true,
colors = ButtonDefaults.buttonColors(
containerColor = Color.Blue,
contentColor = Color.White
)
) {
// Button 的内容区域,可以放任何 Composable
Text(text = "点击我")
}
}
关键点:
Button的content参数(花括号内的内容)可以是 任意 Composable,不一定是 Text。你可以放 Image、Icon、Row 等onClick是必须传入的参数,定义了点击事件enabled控制按钮是否可点击
其他按钮变体:
// 描边按钮
OutlinedButton(onClick = { }) {
Text("Outlined Button")
}
// 文字按钮
TextButton(onClick = { }) {
Text("Text Button")
}
// 带图标的按钮
Button(onClick = { }) {
Icon(Icons.Default.Add, contentDescription = "添加")
Spacer(modifier = Modifier.width(8.dp))
Text("添加")
}
4.3 TextField:文本输入框
文本输入框用来接收用户输入:
@Composable
fun TextFieldExample() {
// 定义一个可变状态来存储输入内容
var input by remember { mutableStateOf("") }
OutlinedTextField(
value = input,
onValueChange = { input = it },
label = { Text("用户名") },
placeholder = { Text("请输入用户名") },
singleLine = true,
isError = input.length > 10,
supportingText = {
if (input.length > 10) {
Text("用户名不能超过10个字符", color = MaterialTheme.colorScheme.error)
}
}
)
}
关键概念——State(状态):
你可能注意到了 remember 和 mutableStateOf——这是 Compose 中管理状态的机制。简单来说:
mutableStateOf("")创建了一个可观察的状态remember保证这个状态在重组(界面刷新)时不被重置onValueChange在每次输入变化时回调,我们把新值更新到状态中
关于 State 的详细讲解在第二篇文章中,这里先记住用法即可。
常用参数:
| 参数 | 说明 |
|---|---|
value | 当前输入框的内容 |
onValueChange | 内容变化时的回调 |
label | 标签(显示在输入框上方或内部) |
placeholder | 占位提示文字 |
singleLine | 是否单行输入 |
isError | 是否显示错误状态 |
keyboardOptions | 键盘配置(数字键盘、邮箱键盘等) |
visualTransformation | 视觉变换(如密码遮罩 PasswordVisualTransformation) |
密码输入框示例:
@Composable
fun PasswordField() {
var password by remember { mutableStateOf("") }
OutlinedTextField(
value = password,
onValueChange = { password = it },
label = { Text("密码") },
visualTransformation = PasswordVisualTransformation(),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password)
)
}
4.4 Image:图片显示
Image 用来显示图片资源:
@Composable
fun ImageExample() {
Image(
painter = painterResource(id = R.drawable.my_image),
contentDescription = "图片描述",
modifier = Modifier.size(200.dp),
contentScale = ContentScale.Crop
)
}
常用参数:
| 参数 | 说明 |
|---|---|
painter | 图片绘制器,painterResource() 加载本地图片 |
contentDescription | 无障碍描述,纯装饰性图片可传 null |
contentScale | 图片缩放模式(Crop 裁剪、Fit 适应、Fill 填充等) |
alpha | 透明度(0f ~ 1f) |
常用 ContentScale 模式:
ContentScale.Crop // 裁剪居中(类似 XML 的 centerCrop)
ContentScale.Fit // 等比缩放,可能留白(类似 fitCenter)
ContentScale.FillBounds // 拉伸填充(类似 fitXY)
ContentScale.Inside // 缩小到容器内,不放大
painterResource()会自动适配不同密度的图片资源,加载方式与 XML 中的R.drawable.xxx一致。 如果是从网络加载图片,需要使用Coil等三方库的AsyncImage,这是后话。
4.5 Spacer:占位间距
Spacer 用来在布局中插入空白区域:
Spacer(modifier = Modifier.height(16.dp)) // 垂直间距
Spacer(modifier = Modifier.width(8.dp)) // 水平间距
五、Modifier 详解
Modifier 是 Compose 中最核心的概念之一。它用来装饰或增强一个 Composable 的外观和交互行为。
5.1 使用方式
几乎所有 Composable 都接收一个可选的 modifier 参数:
Text(
text = "Hello",
modifier = Modifier
.padding(16.dp) // 设置内边距
.background(Color.Yellow) // 设置背景色
.clickable { /* 点击 */ } // 设置点击
.fillMaxWidth() // 填充最大宽度
)
5.2 链式调用与顺序
Modifier 通过链式调用组合多个行为,而且顺序很重要:
// 顺序一:先 padding 再 background
@Composable
fun ModifierOrder1() {
Text(
text = "Hello",
modifier = Modifier
.padding(16.dp) // 先给文字周围留 16dp 空白
.background(Color.Red) // 再给整个区域(含 padding)上红色背景
)
}
// 顺序二:先 background 再 padding
@Composable
fun ModifierOrder2() {
Text(
text = "Hello",
modifier = Modifier
.background(Color.Red) // 先给文字本身加上红色背景
.padding(16.dp) // 再在红色背景周围留白
)
}
两种顺序的效果完全不同。用下面的图来看更直观:
flowchart LR
subgraph 顺序一_padding_then_background
A1[Text 文字] --> A2[padding 16dp 扩大区域]
A2 --> A3[background Red 给整个区域上色]
end
subgraph 顺序二_background_then_padding
B1[Text 文字] --> B2[background Red 仅文字区域上色]
B2 --> B3[padding 16dp 在红色区域外留白]
end
- 顺序一:padding 区域也会被染成红色(padding 在 background 内部)
- 顺序二:padding 区域是透明的(padding 在 background 外部)
记住原则: Modifier 的执行顺序是从左到右的,每个 Modifier 会包裹前一个 Modifier 的结果。
5.3 常用 Modifier 速查
| Modifier | 作用 |
|---|---|
.padding(all = 16.dp) | 内边距 |
.padding(start = 8.dp, top = 16.dp) | 指定方向的内边距 |
.size(48.dp) | 宽高设为固定值 |
.width(100.dp) | 宽度固定 |
.height(100.dp) | 高度固定 |
.fillMaxWidth() | 撑满父容器宽度 |
.fillMaxHeight() | 撑满父容器高度 |
.fillMaxSize() | 撑满父容器 |
.background(Color.Blue) | 背景色 |
.background(Color.Blue, shape = RoundedCornerShape(8.dp)) | 圆角背景 |
.clickable { } | 点击事件 |
.border(width = 1.dp, color = Color.Gray) | 边框 |
.border(width = 1.dp, color = Color.Gray, shape = RoundedCornerShape(8.dp)) | 圆角边框 |
.clip(RoundedCornerShape(8.dp)) | 裁剪为圆角 |
.offset(x = 10.dp, y = 10.dp) | 偏移位置 |
.alpha(0.5f) | 透明度 |
.rotate(45f) | 旋转角度 |
.weight(1f) | 在 Row/Column 中分配权重(类似 LinearLayout 的 weight) |
六、实战:一个简单登录界面
把上面的知识串起来,写一个完整的登录界面:
@Composable
fun LoginScreen() {
// 状态
var username by remember { mutableStateOf("") }
var password by remember { mutableStateOf("") }
// Column 是垂直布局容器,相当于 LinearLayout(vertical)
Column(
modifier = Modifier
.fillMaxSize()
.padding(24.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
// 标题
Text(
text = "欢迎登录",
fontSize = 28.sp,
fontWeight = FontWeight.Bold,
color = MaterialTheme.colorScheme.primary
)
Spacer(modifier = Modifier.height(32.dp))
// 用户名输入框
OutlinedTextField(
value = username,
onValueChange = { username = it },
label = { Text("用户名") },
singleLine = true,
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(16.dp))
// 密码输入框
OutlinedTextField(
value = password,
onValueChange = { password = it },
label = { Text("密码") },
singleLine = true,
visualTransformation = PasswordVisualTransformation(),
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(24.dp))
// 登录按钮
Button(
onClick = { /* 执行登录 */ },
modifier = Modifier
.fillMaxWidth()
.height(50.dp),
enabled = username.isNotBlank() && password.isNotBlank()
) {
Text(text = "登录", fontSize = 18.sp)
}
}
}
把这个 Composable 放到 Activity 的 setContent 中:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MaterialTheme {
LoginScreen()
}
}
}
}
效果说明:居中显示的"欢迎登录"标题,两个输入框,底部一个登录按钮。用户名或密码为空时按钮为禁用状态。
整个登录界面的组件树结构如下:
flowchart TB
A[LoginScreen] --> B[Column<br/>垂直居中]
B --> C[Text<br/>欢迎登录]
B --> D[Spacer 32dp]
B --> E[OutlinedTextField<br/>用户名]
B --> F[Spacer 16dp]
B --> G[OutlinedTextField<br/>密码]
B --> H[Spacer 24dp]
B --> I[Button<br/>登录<br/>enabled 受状态控制]
七、注意事项与小技巧
7.1 避免在 Composable 函数中写耗时操作
// ❌ 错误:在 Composable 中直接执行耗时操作
@Composable
fun BadExample() {
val result = someHeavyComputation() // Compose 可能频繁重组,导致卡顿
Text(text = result)
}
// ✅ 正确:使用 LaunchedEffect 或回调
@Composable
fun GoodExample() {
var result by remember { mutableStateOf("") }
LaunchedEffect(Unit) {
result = someHeavyComputation() // 在协程中执行
}
Text(text = result)
}
7.2 Modifier 参数尽量暴露出去
// ✅ 好的实践:将 modifier 作为参数并提供默认值
@Composable
fun MyCustomButton(
text: String,
onClick: () -> Unit,
modifier: Modifier = Modifier
) {
Button(
onClick = onClick,
modifier = modifier
) {
Text(text = text)
}
}
这样调用方可以自由定制按钮的样式和行为。
7.3 资源引用
在 Compose 中获取颜色、字符串、尺寸等资源:
// 字符串资源
val appName = stringResource(id = R.string.app_name)
// 颜色资源(如果使用了 Material3 的话推荐直接用 MaterialTheme)
val customColor = colorResource(id = R.color.custom_color)
// 尺寸资源
val dimen = dimensionResource(id = R.dimen.custom_dimen)
八、总结
这篇文章我们学习了:
- Compose 的核心概念:声明式 UI 与命令式 UI 的区别
- 环境搭建:Gradle 配置、BOM 的使用
- Composable 函数:基本规范和注意事项
- 基础控件:Text、Button、OutlinedTextField、Image、Spacer
- Modifier:链式调用、执行顺序、常用 Modifier 速查
- 实战:一个完整的登录界面
这些知识足以让你写出简单的 Compose 页面了。下一篇文章我们将进一步探讨 布局系统(Column、Row、Box、LazyColumn 等)和 State 管理(remember、状态提升、StateFlow 收集),这些是写出复杂交互界面的基础。
如果你在搭建过程中遇到任何问题,欢迎在评论区留言交流。
1.1 什么是 Compose?
Jetpack Compose 是 Google 在 2021 年正式推出的 Android 原生 UI 工具包——它不依赖 XML,而是用 Kotlin 代码直接"描述"界面长什么样。
来做个对比你就明白了。以前用 XML + View 体系写界面,大致是三步走:
// 第一步:在 XML 里定义好布局
// 第二步:在 Activity 里 findViewById 找到控件
// 第三步:调用 setText()、setOnClickListener() 手动更新
这套模式叫命令式 UI——你得像下指令一样告诉程序每一步该做什么。而 Compose 的做法完全不同:
// 你只需要描述:"这里有一个文本,内容是 Hello"
Text(text = "Hello")
你说"界面应该长这样",框架自己判断什么时候该更新、更新哪里。这就是声明式 UI。
一句话总结: 命令式是你指挥细节,声明式是你描述结果。门槛更低,代码更少。
用一张图来对比两种模式的工作流程:
flowchart LR
subgraph 命令式_Imperative
A[XML 定义布局] --> B[findViewById 找控件]
B --> C[setText/setOnClickListener 手动更新]
end
subgraph 声明式_Declarative
D[Composable 函数描述界面] --> E[状态变化自动触发重组]
end
命令式_Imperative -.->|vs| 声明式_Declarative
左边命令式:你要自己找到控件、自己更新。右边声明式:你说长什么样,框架管更新。
1.2 Compose 的优势
- 更少的代码:一个 Text 控件从定义到展示,只需要一行代码
- 直观的状态管理:状态变化自动触发界面重组(Recompose),无需手动更新
- 强大的可组合性:小而独立的 Composable 函数自由组合
- 完全用 Kotlin 编写:可以使用 Kotlin 的所有语言特性(高阶函数、协程等)
- 与现有 View 体系互通:可以在 Compose 中嵌入 View,也可以在 View 中嵌入 Compose
二、环境搭建
2.1 Android Studio 版本
Compose 需要 Android Studio Arctic Fox(2020.3.1)或更高版本。建议直接使用最新的稳定版 Android Studio。
2.2 创建支持 Compose 的项目
如果你从模板创建项目,Android Studio 提供了 "Empty Compose Activity" 模板,勾选后会自动配置好所有依赖。
如果是已有项目要接入 Compose,需要手动配置以下内容。
2.3 Gradle 配置
第一步:设置 Kotlin 和 Compose 编译器
在项目根目录的 build.gradle.kts(或 build.gradle)中:
// build.gradle.kts(项目级)
plugins {
id("org.jetbrains.kotlin.android") version "1.9.22" apply false
}
第二步:添加 Compose BOM 和依赖
在模块的 build.gradle.kts 中:
// build.gradle.kts(模块级)
android {
// 需要启用 Compose
buildFeatures {
compose = true
}
}
dependencies {
// BOM(Bill of Materials):统一管理 Compose 版本,避免版本冲突
val composeBom = platform("androidx.compose:compose-bom:2024.09.00")
implementation(composeBom)
// UI 基础
implementation("androidx.compose.ui:ui")
// UI 图形工具
implementation("androidx.compose.ui:ui-graphics")
// UI 预览(只在 debug 模式下需要)
implementation("androidx.compose.ui:ui-tooling-preview")
// Material 3 设计系统
implementation("androidx.compose.material3:material3")
// Activity Compose(setContent 扩展)
implementation("androidx.activity:activity-compose:1.8.0")
// 调试工具
debugImplementation("androidx.compose.ui:ui-tooling")
}
注意:
kotlinCompilerExtensionVersion必须与 Kotlin 版本匹配,具体对应关系可以查看 Compose 与 Kotlin 版本兼容表。
BOM 是什么? BOM(Bill of Materials)是一份"材料清单",你在 dependencies 中声明 Compose 库时不用写具体版本号,BOM 会自动为你选择兼容的版本。这样既不用记版本号,也不用担心版本冲突。
三、第一个 Compose 程序
3.1 Hello World
创建一个最简单的 Compose Activity:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// setContent 是 Activity 的扩展函数,用于设置 Compose 界面
setContent {
// 这里写 Compose 代码
Text(text = "Hello Compose!")
}
}
}
就这么简单。setContent 是 activity-compose 提供的扩展函数,它接受一个 @Composable 函数作为参数——所有 Compose 代码都在这里编写。
整个调用链的关系可以这样理解:
flowchart TB
A[Activity.onCreate] --> B[setContent 扩展函数]
B --> C[Composable 作用域建立]
C --> D[Text<br/>Hello Compose!]
style A fill:#e1f5fe
style B fill:#fff3e0
style C fill:#e8f5e9
style D fill:#fce4ec
3.2 Composable 函数
Text 是一个Composable 函数。任何被 @Composable 注解标记的函数都称为 Composable 函数:
@Composable
fun Greeting(name: String) {
Text(text = "Hello, $name!")
}
Composable 函数有两个硬性规则,刚接触时特别容易忽略:
- 函数名必须以大写字母开头。 这不是什么玄学——Compose 利用这个约定来区分"这是一个 Composable 界面组件"和"这是一个普通工具函数"。如果你用小写开头,编译器不会报错,但团队约定和 IDE 提示都会默认按大写走
- 只能在另一个 Composable 函数的作用域中调用 Composable 函数。 简单说,
setContent { }的花括号里、或者在某个@Composable fun xxx()里,才能调用别的 Composable。在普通 Kotlin 函数里直接调用Text()会编译报错
所以上面的 Activity 可以改写成:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Greeting(name = "Compose")
}
}
}
@Composable
fun Greeting(name: String) {
Text(text = "Hello, $name!")
}
3.3 主题和预览
为了让界面更好看且贴近 Material Design,通常会用 MaterialTheme 包裹:
setContent {
MaterialTheme {
Greeting(name = "Compose")
}
}
另外,Compose 提供了预览功能——用 @Preview 注解标注一个 Composable 函数,就可以在 Android Studio 的 Design 面板中实时看到效果,无需运行到真机:
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
MaterialTheme {
Greeting(name = "Compose")
}
}
@Preview只能标注不接收参数或参数有默认值的 Composable 函数,因为预览时无法传入参数。
四、基础控件详解
接下来逐个介绍最常用的 Compose 控件。每种控件我都会给出主要参数说明和完整的示例代码。
4.1 Text:文本显示
Text 是最基础的控件,用来显示文字:
@Composable
fun TextExample() {
Text(
text = "Hello Compose",
color = Color.Red,
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
textAlign = TextAlign.Center,
maxLines = 2,
overflow = TextOverflow.Ellipsis
)
}
常用参数:
| 参数 | 类型 | 说明 |
|---|---|---|
text | String / AnnotatedString | 要显示的文本 |
color | Color | 文字颜色 |
fontSize | TextUnit(sp) | 字体大小,用 .sp 单位 |
fontWeight | FontWeight | 字重(Bold、Light、Normal 等) |
textAlign | TextAlign | 对齐方式(Start、Center、End 等) |
maxLines | Int | 最大行数 |
overflow | TextOverflow | 超出时的处理方式(Ellipsis 省略号、Clip 裁剪) |
style | TextStyle | 统一样式设置,包含上述所有属性 |
单位说明:Compose 中使用
.dp(独立密度像素)表示尺寸,.sp(缩放独立像素)表示字体大小,这和 XML 中的 dp/sp 含义一致。
以上全部参数只是 Text 的一部分,更多参数可以在 IDE 中按 Ctrl+P(Windows)或 Command+P(Mac)查看。
4.2 Button:按钮
Button 是 Material 3 的按钮组件:
@Composable
fun ButtonExample() {
Button(
onClick = { /* 点击回调 */ },
enabled = true,
colors = ButtonDefaults.buttonColors(
containerColor = Color.Blue,
contentColor = Color.White
)
) {
// Button 的内容区域,可以放任何 Composable
Text(text = "点击我")
}
}
关键点:
Button的content参数(花括号内的内容)可以是 任意 Composable,不一定是 Text。你可以放 Image、Icon、Row 等onClick是必须传入的参数,定义了点击事件enabled控制按钮是否可点击
其他按钮变体:
// 描边按钮
OutlinedButton(onClick = { }) {
Text("Outlined Button")
}
// 文字按钮
TextButton(onClick = { }) {
Text("Text Button")
}
// 带图标的按钮
Button(onClick = { }) {
Icon(Icons.Default.Add, contentDescription = "添加")
Spacer(modifier = Modifier.width(8.dp))
Text("添加")
}
4.3 TextField:文本输入框
文本输入框用来接收用户输入:
@Composable
fun TextFieldExample() {
// 定义一个可变状态来存储输入内容
var input by remember { mutableStateOf("") }
OutlinedTextField(
value = input,
onValueChange = { input = it },
label = { Text("用户名") },
placeholder = { Text("请输入用户名") },
singleLine = true,
isError = input.length > 10,
supportingText = {
if (input.length > 10) {
Text("用户名不能超过10个字符", color = MaterialTheme.colorScheme.error)
}
}
)
}
关键概念——State(状态):
你可能注意到了 remember 和 mutableStateOf——这是 Compose 中管理状态的机制。简单来说:
mutableStateOf("")创建了一个可观察的状态remember保证这个状态在重组(界面刷新)时不被重置onValueChange在每次输入变化时回调,我们把新值更新到状态中
关于 State 的详细讲解在第二篇文章中,这里先记住用法即可。
常用参数:
| 参数 | 说明 |
|---|---|
value | 当前输入框的内容 |
onValueChange | 内容变化时的回调 |
label | 标签(显示在输入框上方或内部) |
placeholder | 占位提示文字 |
singleLine | 是否单行输入 |
isError | 是否显示错误状态 |
keyboardOptions | 键盘配置(数字键盘、邮箱键盘等) |
visualTransformation | 视觉变换(如密码遮罩 PasswordVisualTransformation) |
密码输入框示例:
@Composable
fun PasswordField() {
var password by remember { mutableStateOf("") }
OutlinedTextField(
value = password,
onValueChange = { password = it },
label = { Text("密码") },
visualTransformation = PasswordVisualTransformation(),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password)
)
}
4.4 Image:图片显示
Image 用来显示图片资源:
@Composable
fun ImageExample() {
Image(
painter = painterResource(id = R.drawable.my_image),
contentDescription = "图片描述",
modifier = Modifier.size(200.dp),
contentScale = ContentScale.Crop
)
}
常用参数:
| 参数 | 说明 |
|---|---|
painter | 图片绘制器,painterResource() 加载本地图片 |
contentDescription | 无障碍描述,纯装饰性图片可传 null |
contentScale | 图片缩放模式(Crop 裁剪、Fit 适应、Fill 填充等) |
alpha | 透明度(0f ~ 1f) |
常用 ContentScale 模式:
ContentScale.Crop // 裁剪居中(类似 XML 的 centerCrop)
ContentScale.Fit // 等比缩放,可能留白(类似 fitCenter)
ContentScale.FillBounds // 拉伸填充(类似 fitXY)
ContentScale.Inside // 缩小到容器内,不放大
painterResource()会自动适配不同密度的图片资源,加载方式与 XML 中的R.drawable.xxx一致。 如果是从网络加载图片,需要使用Coil等三方库的AsyncImage,这是后话。
4.5 Spacer:占位间距
Spacer 用来在布局中插入空白区域:
Spacer(modifier = Modifier.height(16.dp)) // 垂直间距
Spacer(modifier = Modifier.width(8.dp)) // 水平间距
五、Modifier 详解
Modifier 是 Compose 中最核心的概念之一。它用来装饰或增强一个 Composable 的外观和交互行为。
5.1 使用方式
几乎所有 Composable 都接收一个可选的 modifier 参数:
Text(
text = "Hello",
modifier = Modifier
.padding(16.dp) // 设置内边距
.background(Color.Yellow) // 设置背景色
.clickable { /* 点击 */ } // 设置点击
.fillMaxWidth() // 填充最大宽度
)
5.2 链式调用与顺序
Modifier 通过链式调用组合多个行为,而且顺序很重要:
// 顺序一:先 padding 再 background
@Composable
fun ModifierOrder1() {
Text(
text = "Hello",
modifier = Modifier
.padding(16.dp) // 先给文字周围留 16dp 空白
.background(Color.Red) // 再给整个区域(含 padding)上红色背景
)
}
// 顺序二:先 background 再 padding
@Composable
fun ModifierOrder2() {
Text(
text = "Hello",
modifier = Modifier
.background(Color.Red) // 先给文字本身加上红色背景
.padding(16.dp) // 再在红色背景周围留白
)
}
两种顺序的效果完全不同。用下面的图来看更直观:
flowchart LR
subgraph 顺序一_padding_then_background
A1[Text 文字] --> A2[padding 16dp 扩大区域]
A2 --> A3[background Red 给整个区域上色]
end
subgraph 顺序二_background_then_padding
B1[Text 文字] --> B2[background Red 仅文字区域上色]
B2 --> B3[padding 16dp 在红色区域外留白]
end
- 顺序一:padding 区域也会被染成红色(padding 在 background 内部)
- 顺序二:padding 区域是透明的(padding 在 background 外部)
记住原则: Modifier 的执行顺序是从左到右的,每个 Modifier 会包裹前一个 Modifier 的结果。
5.3 常用 Modifier 速查
| Modifier | 作用 |
|---|---|
.padding(all = 16.dp) | 内边距 |
.padding(start = 8.dp, top = 16.dp) | 指定方向的内边距 |
.size(48.dp) | 宽高设为固定值 |
.width(100.dp) | 宽度固定 |
.height(100.dp) | 高度固定 |
.fillMaxWidth() | 撑满父容器宽度 |
.fillMaxHeight() | 撑满父容器高度 |
.fillMaxSize() | 撑满父容器 |
.background(Color.Blue) | 背景色 |
.background(Color.Blue, shape = RoundedCornerShape(8.dp)) | 圆角背景 |
.clickable { } | 点击事件 |
.border(width = 1.dp, color = Color.Gray) | 边框 |
.border(width = 1.dp, color = Color.Gray, shape = RoundedCornerShape(8.dp)) | 圆角边框 |
.clip(RoundedCornerShape(8.dp)) | 裁剪为圆角 |
.offset(x = 10.dp, y = 10.dp) | 偏移位置 |
.alpha(0.5f) | 透明度 |
.rotate(45f) | 旋转角度 |
.weight(1f) | 在 Row/Column 中分配权重(类似 LinearLayout 的 weight) |
六、实战:一个简单登录界面
把上面的知识串起来,写一个完整的登录界面:
@Composable
fun LoginScreen() {
// 状态
var username by remember { mutableStateOf("") }
var password by remember { mutableStateOf("") }
// Column 是垂直布局容器,相当于 LinearLayout(vertical)
Column(
modifier = Modifier
.fillMaxSize()
.padding(24.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
// 标题
Text(
text = "欢迎登录",
fontSize = 28.sp,
fontWeight = FontWeight.Bold,
color = MaterialTheme.colorScheme.primary
)
Spacer(modifier = Modifier.height(32.dp))
// 用户名输入框
OutlinedTextField(
value = username,
onValueChange = { username = it },
label = { Text("用户名") },
singleLine = true,
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(16.dp))
// 密码输入框
OutlinedTextField(
value = password,
onValueChange = { password = it },
label = { Text("密码") },
singleLine = true,
visualTransformation = PasswordVisualTransformation(),
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(24.dp))
// 登录按钮
Button(
onClick = { /* 执行登录 */ },
modifier = Modifier
.fillMaxWidth()
.height(50.dp),
enabled = username.isNotBlank() && password.isNotBlank()
) {
Text(text = "登录", fontSize = 18.sp)
}
}
}
把这个 Composable 放到 Activity 的 setContent 中:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MaterialTheme {
LoginScreen()
}
}
}
}
效果说明:居中显示的"欢迎登录"标题,两个输入框,底部一个登录按钮。用户名或密码为空时按钮为禁用状态。
整个登录界面的组件树结构如下:
flowchart TB
A[LoginScreen] --> B[Column<br/>垂直居中]
B --> C[Text<br/>欢迎登录]
B --> D[Spacer 32dp]
B --> E[OutlinedTextField<br/>用户名]
B --> F[Spacer 16dp]
B --> G[OutlinedTextField<br/>密码]
B --> H[Spacer 24dp]
B --> I[Button<br/>登录<br/>enabled 受状态控制]
七、注意事项与小技巧
7.1 避免在 Composable 函数中写耗时操作
// ❌ 错误:在 Composable 中直接执行耗时操作
@Composable
fun BadExample() {
val result = someHeavyComputation() // Compose 可能频繁重组,导致卡顿
Text(text = result)
}
// ✅ 正确:使用 LaunchedEffect 或回调
@Composable
fun GoodExample() {
var result by remember { mutableStateOf("") }
LaunchedEffect(Unit) {
result = someHeavyComputation() // 在协程中执行
}
Text(text = result)
}
7.2 Modifier 参数尽量暴露出去
// ✅ 好的实践:将 modifier 作为参数并提供默认值
@Composable
fun MyCustomButton(
text: String,
onClick: () -> Unit,
modifier: Modifier = Modifier
) {
Button(
onClick = onClick,
modifier = modifier
) {
Text(text = text)
}
}
这样调用方可以自由定制按钮的样式和行为。
7.3 资源引用
在 Compose 中获取颜色、字符串、尺寸等资源:
// 字符串资源
val appName = stringResource(id = R.string.app_name)
// 颜色资源(如果使用了 Material3 的话推荐直接用 MaterialTheme)
val customColor = colorResource(id = R.color.custom_color)
// 尺寸资源
val dimen = dimensionResource(id = R.dimen.custom_dimen)
八、总结
这篇文章我们学习了:
- Compose 的核心概念:声明式 UI 与命令式 UI 的区别
- 环境搭建:Gradle 配置、BOM 的使用
- Composable 函数:基本规范和注意事项
- 基础控件:Text、Button、OutlinedTextField、Image、Spacer
- Modifier:链式调用、执行顺序、常用 Modifier 速查
- 实战:一个完整的登录界面
这些知识足以让你写出简单的 Compose 页面了。下一篇文章我们将进一步探讨 布局系统(Column、Row、Box、LazyColumn 等)和 State 管理(remember、状态提升、StateFlow 收集),这些是写出复杂交互界面的基础。
如果你在搭建过程中遇到任何问题,欢迎在评论区留言交流。