Jetpack Compose 入门系列(一):从零搭建到基础控件使用

Jetpack Compose 入门系列(一):从零搭建到基础控件使用

一、前言

一直用 XML + View 写界面?Jetpack Compose 是你该学的新方向。

1.1 什么是 Compose?

Jetpack Compose 是 Google 在 2021 年正式推出的 Android 原生声明式 UI 框架------它不依赖 XML,而是用 Kotlin 代码直接"描述"界面长什么样。

来做个对比你就明白了。以前用 XML + View 体系写界面,大致是三步走:

kotlin 复制代码
// 第一步:在 XML 里定义好布局
// 第二步:在 Activity 里 findViewById 找到控件
// 第三步:调用 setText()、setOnClickListener() 手动更新

这套模式叫命令式 UI------你得像下指令一样告诉程序每一步该做什么。而 Compose 的做法完全不同:

kotlin 复制代码
// 你只需要描述:"这里有一个文本,内容是 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 体系写界面,大致是三步走:

kotlin 复制代码
// 第一步:在 XML 里定义好布局
// 第二步:在 Activity 里 findViewById 找到控件
// 第三步:调用 setText()、setOnClickListener() 手动更新

这套模式叫命令式 UI------你得像下指令一样告诉程序每一步该做什么。而 Compose 的做法完全不同:

kotlin 复制代码
// 你只需要描述:"这里有一个文本,内容是 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中:

kotlin 复制代码
// build.gradle.kts(项目级)
plugins {
    alias(libs.plugins.android.application) apply false
    alias(libs.plugins.kotlin.compose) apply false
}
第二步:声明依赖和指定版本

gradle/libs.versions.toml 声明依赖和指定版本:

ini 复制代码
// 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 中:

kotlin 复制代码
// 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:

kotlin 复制代码
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // setContent 是 Activity 的扩展函数,用于设置 Compose 界面
        setContent {
            // 这里写 Compose 代码
            Text(text = "Hello Compose!")
        }
    }
}

就这么简单。setContentactivity-compose 提供的扩展函数,它接受一个 @Composable 函数作为参数------所有 Compose 代码都在这里编写。

整个调用链的关系可以这样理解:

flowchart TB A[Activity.onCreate] --> B[setContent 扩展函数] B --> C[Composable 作用域建立] C --> D[Text
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 函数:

kotlin 复制代码
@Composable
fun Greeting(name: String) {
    Text(text = "Hello, $name!")
}

Composable 函数有两个硬性规则,刚接触时特别容易忽略:

  1. 函数名必须以大写字母开头。 这不是什么玄学------Compose 利用这个约定来区分"这是一个 Composable 界面组件"和"这是一个普通工具函数"。如果你用小写开头,编译器不会报错,但团队约定和 IDE 提示都会默认按大写走
  2. 只能在另一个 Composable 函数的作用域中调用 Composable 函数。 简单说,setContent { } 的花括号里、或者在某个 @Composable fun xxx() 里,才能调用别的 Composable。在普通 Kotlin 函数里直接调用 Text() 会编译报错

所以上面的 Activity 可以改写成:

kotlin 复制代码
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 包裹:

kotlin 复制代码
setContent {
    MaterialTheme {
        Greeting(name = "Compose")
    }
}

另外,Compose 提供了预览功能 ------用 @Preview 注解标注一个 Composable 函数,就可以在 Android Studio 的 Design 面板中实时看到效果,无需运行到真机:

kotlin 复制代码
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
    MaterialTheme {
        Greeting(name = "Compose")
    }
}

@Preview 只能标注不接收参数或参数有默认值的 Composable 函数,因为预览时无法传入参数。


四、基础控件详解

接下来逐个介绍最常用的 Compose 控件。每种控件我都会给出主要参数说明和完整的示例代码。

4.1 Text:文本显示

Text 是最基础的控件,用来显示文字:

kotlin 复制代码
@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 的按钮组件:

kotlin 复制代码
@Composable
fun ButtonExample() {
    Button(
        onClick = { /* 点击回调 */ },
        enabled = true,
        colors = ButtonDefaults.buttonColors(
            containerColor = Color.Blue,
            contentColor = Color.White
        )
    ) {
        // Button 的内容区域,可以放任何 Composable
        Text(text = "点击我")
    }
}

关键点:

  • Buttoncontent 参数(花括号内的内容)可以是 任意 Composable,不一定是 Text。你可以放 Image、Icon、Row 等
  • onClick 是必须传入的参数,定义了点击事件
  • enabled 控制按钮是否可点击

其他按钮变体:

kotlin 复制代码
// 描边按钮
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:文本输入框

文本输入框用来接收用户输入:

kotlin 复制代码
@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(状态):

你可能注意到了 remembermutableStateOf------这是 Compose 中管理状态的机制。简单来说:

  • mutableStateOf("") 创建了一个可观察的状态
  • remember 保证这个状态在重组(界面刷新)时不被重置
  • onValueChange 在每次输入变化时回调,我们把新值更新到状态中

关于 State 的详细讲解在第二篇文章中,这里先记住用法即可。

常用参数:

参数 说明
value 当前输入框的内容
onValueChange 内容变化时的回调
label 标签(显示在输入框上方或内部)
placeholder 占位提示文字
singleLine 是否单行输入
isError 是否显示错误状态
keyboardOptions 键盘配置(数字键盘、邮箱键盘等)
visualTransformation 视觉变换(如密码遮罩 PasswordVisualTransformation)

密码输入框示例:

kotlin 复制代码
@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 用来显示图片资源:

kotlin 复制代码
@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 模式:

kotlin 复制代码
ContentScale.Crop      // 裁剪居中(类似 XML 的 centerCrop)
ContentScale.Fit       // 等比缩放,可能留白(类似 fitCenter)
ContentScale.FillBounds // 拉伸填充(类似 fitXY)
ContentScale.Inside    // 缩小到容器内,不放大

painterResource() 会自动适配不同密度的图片资源,加载方式与 XML 中的 R.drawable.xxx 一致。 如果是从网络加载图片,需要使用 Coil 等三方库的 AsyncImage,这是后话。

4.5 Spacer:占位间距

Spacer 用来在布局中插入空白区域:

kotlin 复制代码
Spacer(modifier = Modifier.height(16.dp))  // 垂直间距
Spacer(modifier = Modifier.width(8.dp))    // 水平间距

五、Modifier 详解

Modifier 是 Compose 中最核心的概念之一。它用来装饰或增强一个 Composable 的外观和交互行为。

5.1 使用方式

几乎所有 Composable 都接收一个可选的 modifier 参数:

kotlin 复制代码
Text(
    text = "Hello",
    modifier = Modifier
        .padding(16.dp)          // 设置内边距
        .background(Color.Yellow) // 设置背景色
        .clickable { /* 点击 */ }  // 设置点击
        .fillMaxWidth()          // 填充最大宽度
)

5.2 链式调用与顺序

Modifier 通过链式调用组合多个行为,而且顺序很重要

kotlin 复制代码
// 顺序一:先 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)

六、实战:一个简单登录界面

把上面的知识串起来,写一个完整的登录界面:

kotlin 复制代码
@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 中:

kotlin 复制代码
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MaterialTheme {
                LoginScreen()
            }
        }
    }
}

效果说明:居中显示的"欢迎登录"标题,两个输入框,底部一个登录按钮。用户名或密码为空时按钮为禁用状态。

整个登录界面的组件树结构如下:

flowchart TB A[LoginScreen] --> B[Column
垂直居中] B --> C[Text
欢迎登录] B --> D[Spacer 32dp] B --> E[OutlinedTextField
用户名] B --> F[Spacer 16dp] B --> G[OutlinedTextField
密码] B --> H[Spacer 24dp] B --> I[Button
登录
enabled 受状态控制]

七、注意事项与小技巧

7.1 避免在 Composable 函数中写耗时操作

kotlin 复制代码
// ❌ 错误:在 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 参数尽量暴露出去

kotlin 复制代码
// ✅ 好的实践:将 modifier 作为参数并提供默认值
@Composable
fun MyCustomButton(
    text: String,
    onClick: () -> Unit,
    modifier: Modifier = Modifier
) {
    Button(
        onClick = onClick,
        modifier = modifier
    ) {
        Text(text = text)
    }
}

这样调用方可以自由定制按钮的样式和行为。

7.3 资源引用

在 Compose 中获取颜色、字符串、尺寸等资源:

kotlin 复制代码
// 字符串资源
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)

八、总结

这篇文章我们学习了:

  1. Compose 的核心概念:声明式 UI 与命令式 UI 的区别
  2. 环境搭建:Gradle 配置、BOM 的使用
  3. Composable 函数:基本规范和注意事项
  4. 基础控件:Text、Button、OutlinedTextField、Image、Spacer
  5. Modifier:链式调用、执行顺序、常用 Modifier 速查
  6. 实战:一个完整的登录界面

这些知识足以让你写出简单的 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中:

kotlin 复制代码
// build.gradle.kts(项目级)
plugins {
    alias(libs.plugins.android.application) apply false
    alias(libs.plugins.kotlin.compose) apply false
}
第二步:声明依赖和指定版本

gradle/libs.versions.toml 声明依赖和指定版本:

ini 复制代码
// 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 中:

kotlin 复制代码
// 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:

kotlin 复制代码
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // setContent 是 Activity 的扩展函数,用于设置 Compose 界面
        setContent {
            // 这里写 Compose 代码
            Text(text = "Hello Compose!")
        }
    }
}

就这么简单。setContentactivity-compose 提供的扩展函数,它接受一个 @Composable 函数作为参数------所有 Compose 代码都在这里编写。

整个调用链的关系可以这样理解:

flowchart TB A[Activity.onCreate] --> B[setContent 扩展函数] B --> C[Composable 作用域建立] C --> D[Text
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 函数:

kotlin 复制代码
@Composable
fun Greeting(name: String) {
    Text(text = "Hello, $name!")
}

Composable 函数有两个硬性规则,刚接触时特别容易忽略:

  1. 函数名必须以大写字母开头。 这不是什么玄学------Compose 利用这个约定来区分"这是一个 Composable 界面组件"和"这是一个普通工具函数"。如果你用小写开头,编译器不会报错,但团队约定和 IDE 提示都会默认按大写走
  2. 只能在另一个 Composable 函数的作用域中调用 Composable 函数。 简单说,setContent { } 的花括号里、或者在某个 @Composable fun xxx() 里,才能调用别的 Composable。在普通 Kotlin 函数里直接调用 Text() 会编译报错

所以上面的 Activity 可以改写成:

kotlin 复制代码
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 包裹:

kotlin 复制代码
setContent {
    MaterialTheme {
        Greeting(name = "Compose")
    }
}

另外,Compose 提供了预览功能 ------用 @Preview 注解标注一个 Composable 函数,就可以在 Android Studio 的 Design 面板中实时看到效果,无需运行到真机:

kotlin 复制代码
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
    MaterialTheme {
        Greeting(name = "Compose")
    }
}

@Preview 只能标注不接收参数或参数有默认值的 Composable 函数,因为预览时无法传入参数。


四、基础控件详解

接下来逐个介绍最常用的 Compose 控件。每种控件我都会给出主要参数说明和完整的示例代码。

4.1 Text:文本显示

Text 是最基础的控件,用来显示文字:

kotlin 复制代码
@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 的按钮组件:

kotlin 复制代码
@Composable
fun ButtonExample() {
    Button(
        onClick = { /* 点击回调 */ },
        enabled = true,
        colors = ButtonDefaults.buttonColors(
            containerColor = Color.Blue,
            contentColor = Color.White
        )
    ) {
        // Button 的内容区域,可以放任何 Composable
        Text(text = "点击我")
    }
}

关键点:

  • Buttoncontent 参数(花括号内的内容)可以是 任意 Composable,不一定是 Text。你可以放 Image、Icon、Row 等
  • onClick 是必须传入的参数,定义了点击事件
  • enabled 控制按钮是否可点击

其他按钮变体:

kotlin 复制代码
// 描边按钮
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:文本输入框

文本输入框用来接收用户输入:

kotlin 复制代码
@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(状态):

你可能注意到了 remembermutableStateOf------这是 Compose 中管理状态的机制。简单来说:

  • mutableStateOf("") 创建了一个可观察的状态
  • remember 保证这个状态在重组(界面刷新)时不被重置
  • onValueChange 在每次输入变化时回调,我们把新值更新到状态中

关于 State 的详细讲解在第二篇文章中,这里先记住用法即可。

常用参数:

参数 说明
value 当前输入框的内容
onValueChange 内容变化时的回调
label 标签(显示在输入框上方或内部)
placeholder 占位提示文字
singleLine 是否单行输入
isError 是否显示错误状态
keyboardOptions 键盘配置(数字键盘、邮箱键盘等)
visualTransformation 视觉变换(如密码遮罩 PasswordVisualTransformation)

密码输入框示例:

kotlin 复制代码
@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 用来显示图片资源:

kotlin 复制代码
@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 模式:

kotlin 复制代码
ContentScale.Crop      // 裁剪居中(类似 XML 的 centerCrop)
ContentScale.Fit       // 等比缩放,可能留白(类似 fitCenter)
ContentScale.FillBounds // 拉伸填充(类似 fitXY)
ContentScale.Inside    // 缩小到容器内,不放大

painterResource() 会自动适配不同密度的图片资源,加载方式与 XML 中的 R.drawable.xxx 一致。 如果是从网络加载图片,需要使用 Coil 等三方库的 AsyncImage,这是后话。

4.5 Spacer:占位间距

Spacer 用来在布局中插入空白区域:

kotlin 复制代码
Spacer(modifier = Modifier.height(16.dp))  // 垂直间距
Spacer(modifier = Modifier.width(8.dp))    // 水平间距

五、Modifier 详解

Modifier 是 Compose 中最核心的概念之一。它用来装饰或增强一个 Composable 的外观和交互行为。

5.1 使用方式

几乎所有 Composable 都接收一个可选的 modifier 参数:

kotlin 复制代码
Text(
    text = "Hello",
    modifier = Modifier
        .padding(16.dp)          // 设置内边距
        .background(Color.Yellow) // 设置背景色
        .clickable { /* 点击 */ }  // 设置点击
        .fillMaxWidth()          // 填充最大宽度
)

5.2 链式调用与顺序

Modifier 通过链式调用组合多个行为,而且顺序很重要

kotlin 复制代码
// 顺序一:先 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)

六、实战:一个简单登录界面

把上面的知识串起来,写一个完整的登录界面:

kotlin 复制代码
@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 中:

kotlin 复制代码
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MaterialTheme {
                LoginScreen()
            }
        }
    }
}

效果说明:居中显示的"欢迎登录"标题,两个输入框,底部一个登录按钮。用户名或密码为空时按钮为禁用状态。

整个登录界面的组件树结构如下:

flowchart TB A[LoginScreen] --> B[Column
垂直居中] B --> C[Text
欢迎登录] B --> D[Spacer 32dp] B --> E[OutlinedTextField
用户名] B --> F[Spacer 16dp] B --> G[OutlinedTextField
密码] B --> H[Spacer 24dp] B --> I[Button
登录
enabled 受状态控制]

七、注意事项与小技巧

7.1 避免在 Composable 函数中写耗时操作

kotlin 复制代码
// ❌ 错误:在 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 参数尽量暴露出去

kotlin 复制代码
// ✅ 好的实践:将 modifier 作为参数并提供默认值
@Composable
fun MyCustomButton(
    text: String,
    onClick: () -> Unit,
    modifier: Modifier = Modifier
) {
    Button(
        onClick = onClick,
        modifier = modifier
    ) {
        Text(text = text)
    }
}

这样调用方可以自由定制按钮的样式和行为。

7.3 资源引用

在 Compose 中获取颜色、字符串、尺寸等资源:

kotlin 复制代码
// 字符串资源
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)

八、总结

这篇文章我们学习了:

  1. Compose 的核心概念:声明式 UI 与命令式 UI 的区别
  2. 环境搭建:Gradle 配置、BOM 的使用
  3. Composable 函数:基本规范和注意事项
  4. 基础控件:Text、Button、OutlinedTextField、Image、Spacer
  5. Modifier:链式调用、执行顺序、常用 Modifier 速查
  6. 实战:一个完整的登录界面

这些知识足以让你写出简单的 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 体系写界面,大致是三步走:

kotlin 复制代码
// 第一步:在 XML 里定义好布局
// 第二步:在 Activity 里 findViewById 找到控件
// 第三步:调用 setText()、setOnClickListener() 手动更新

这套模式叫命令式 UI------你得像下指令一样告诉程序每一步该做什么。而 Compose 的做法完全不同:

kotlin 复制代码
// 你只需要描述:"这里有一个文本,内容是 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)中:

kotlin 复制代码
// 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 中:

kotlin 复制代码
// 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:

kotlin 复制代码
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // setContent 是 Activity 的扩展函数,用于设置 Compose 界面
        setContent {
            // 这里写 Compose 代码
            Text(text = "Hello Compose!")
        }
    }
}

就这么简单。setContentactivity-compose 提供的扩展函数,它接受一个 @Composable 函数作为参数------所有 Compose 代码都在这里编写。

整个调用链的关系可以这样理解:

flowchart TB A[Activity.onCreate] --> B[setContent 扩展函数] B --> C[Composable 作用域建立] C --> D[Text
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 函数:

kotlin 复制代码
@Composable
fun Greeting(name: String) {
    Text(text = "Hello, $name!")
}

Composable 函数有两个硬性规则,刚接触时特别容易忽略:

  1. 函数名必须以大写字母开头。 这不是什么玄学------Compose 利用这个约定来区分"这是一个 Composable 界面组件"和"这是一个普通工具函数"。如果你用小写开头,编译器不会报错,但团队约定和 IDE 提示都会默认按大写走
  2. 只能在另一个 Composable 函数的作用域中调用 Composable 函数。 简单说,setContent { } 的花括号里、或者在某个 @Composable fun xxx() 里,才能调用别的 Composable。在普通 Kotlin 函数里直接调用 Text() 会编译报错

所以上面的 Activity 可以改写成:

kotlin 复制代码
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 包裹:

kotlin 复制代码
setContent {
    MaterialTheme {
        Greeting(name = "Compose")
    }
}

另外,Compose 提供了预览功能 ------用 @Preview 注解标注一个 Composable 函数,就可以在 Android Studio 的 Design 面板中实时看到效果,无需运行到真机:

kotlin 复制代码
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
    MaterialTheme {
        Greeting(name = "Compose")
    }
}

@Preview 只能标注不接收参数或参数有默认值的 Composable 函数,因为预览时无法传入参数。


四、基础控件详解

接下来逐个介绍最常用的 Compose 控件。每种控件我都会给出主要参数说明和完整的示例代码。

4.1 Text:文本显示

Text 是最基础的控件,用来显示文字:

kotlin 复制代码
@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 的按钮组件:

kotlin 复制代码
@Composable
fun ButtonExample() {
    Button(
        onClick = { /* 点击回调 */ },
        enabled = true,
        colors = ButtonDefaults.buttonColors(
            containerColor = Color.Blue,
            contentColor = Color.White
        )
    ) {
        // Button 的内容区域,可以放任何 Composable
        Text(text = "点击我")
    }
}

关键点:

  • Buttoncontent 参数(花括号内的内容)可以是 任意 Composable,不一定是 Text。你可以放 Image、Icon、Row 等
  • onClick 是必须传入的参数,定义了点击事件
  • enabled 控制按钮是否可点击

其他按钮变体:

kotlin 复制代码
// 描边按钮
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:文本输入框

文本输入框用来接收用户输入:

kotlin 复制代码
@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(状态):

你可能注意到了 remembermutableStateOf------这是 Compose 中管理状态的机制。简单来说:

  • mutableStateOf("") 创建了一个可观察的状态
  • remember 保证这个状态在重组(界面刷新)时不被重置
  • onValueChange 在每次输入变化时回调,我们把新值更新到状态中

关于 State 的详细讲解在第二篇文章中,这里先记住用法即可。

常用参数:

参数 说明
value 当前输入框的内容
onValueChange 内容变化时的回调
label 标签(显示在输入框上方或内部)
placeholder 占位提示文字
singleLine 是否单行输入
isError 是否显示错误状态
keyboardOptions 键盘配置(数字键盘、邮箱键盘等)
visualTransformation 视觉变换(如密码遮罩 PasswordVisualTransformation)

密码输入框示例:

kotlin 复制代码
@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 用来显示图片资源:

kotlin 复制代码
@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 模式:

kotlin 复制代码
ContentScale.Crop      // 裁剪居中(类似 XML 的 centerCrop)
ContentScale.Fit       // 等比缩放,可能留白(类似 fitCenter)
ContentScale.FillBounds // 拉伸填充(类似 fitXY)
ContentScale.Inside    // 缩小到容器内,不放大

painterResource() 会自动适配不同密度的图片资源,加载方式与 XML 中的 R.drawable.xxx 一致。 如果是从网络加载图片,需要使用 Coil 等三方库的 AsyncImage,这是后话。

4.5 Spacer:占位间距

Spacer 用来在布局中插入空白区域:

kotlin 复制代码
Spacer(modifier = Modifier.height(16.dp))  // 垂直间距
Spacer(modifier = Modifier.width(8.dp))    // 水平间距

五、Modifier 详解

Modifier 是 Compose 中最核心的概念之一。它用来装饰或增强一个 Composable 的外观和交互行为。

5.1 使用方式

几乎所有 Composable 都接收一个可选的 modifier 参数:

kotlin 复制代码
Text(
    text = "Hello",
    modifier = Modifier
        .padding(16.dp)          // 设置内边距
        .background(Color.Yellow) // 设置背景色
        .clickable { /* 点击 */ }  // 设置点击
        .fillMaxWidth()          // 填充最大宽度
)

5.2 链式调用与顺序

Modifier 通过链式调用组合多个行为,而且顺序很重要

kotlin 复制代码
// 顺序一:先 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)

六、实战:一个简单登录界面

把上面的知识串起来,写一个完整的登录界面:

kotlin 复制代码
@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 中:

kotlin 复制代码
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MaterialTheme {
                LoginScreen()
            }
        }
    }
}

效果说明:居中显示的"欢迎登录"标题,两个输入框,底部一个登录按钮。用户名或密码为空时按钮为禁用状态。

整个登录界面的组件树结构如下:

flowchart TB A[LoginScreen] --> B[Column
垂直居中] B --> C[Text
欢迎登录] B --> D[Spacer 32dp] B --> E[OutlinedTextField
用户名] B --> F[Spacer 16dp] B --> G[OutlinedTextField
密码] B --> H[Spacer 24dp] B --> I[Button
登录
enabled 受状态控制]

七、注意事项与小技巧

7.1 避免在 Composable 函数中写耗时操作

kotlin 复制代码
// ❌ 错误:在 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 参数尽量暴露出去

kotlin 复制代码
// ✅ 好的实践:将 modifier 作为参数并提供默认值
@Composable
fun MyCustomButton(
    text: String,
    onClick: () -> Unit,
    modifier: Modifier = Modifier
) {
    Button(
        onClick = onClick,
        modifier = modifier
    ) {
        Text(text = text)
    }
}

这样调用方可以自由定制按钮的样式和行为。

7.3 资源引用

在 Compose 中获取颜色、字符串、尺寸等资源:

kotlin 复制代码
// 字符串资源
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)

八、总结

这篇文章我们学习了:

  1. Compose 的核心概念:声明式 UI 与命令式 UI 的区别
  2. 环境搭建:Gradle 配置、BOM 的使用
  3. Composable 函数:基本规范和注意事项
  4. 基础控件:Text、Button、OutlinedTextField、Image、Spacer
  5. Modifier:链式调用、执行顺序、常用 Modifier 速查
  6. 实战:一个完整的登录界面

这些知识足以让你写出简单的 Compose 页面了。下一篇文章我们将进一步探讨 布局系统 (Column、Row、Box、LazyColumn 等)和 State 管理(remember、状态提升、StateFlow 收集),这些是写出复杂交互界面的基础。


如果你在搭建过程中遇到任何问题,欢迎在评论区留言交流。

1.1 什么是 Compose?

Jetpack Compose 是 Google 在 2021 年正式推出的 Android 原生 UI 工具包------它不依赖 XML,而是用 Kotlin 代码直接"描述"界面长什么样。

来做个对比你就明白了。以前用 XML + View 体系写界面,大致是三步走:

kotlin 复制代码
// 第一步:在 XML 里定义好布局
// 第二步:在 Activity 里 findViewById 找到控件
// 第三步:调用 setText()、setOnClickListener() 手动更新

这套模式叫命令式 UI------你得像下指令一样告诉程序每一步该做什么。而 Compose 的做法完全不同:

kotlin 复制代码
// 你只需要描述:"这里有一个文本,内容是 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)中:

kotlin 复制代码
// build.gradle.kts(项目级)
plugins {
    id("org.jetbrains.kotlin.android") version "1.9.22" apply false
}
第二步:添加 Compose BOM 和依赖

在模块的 build.gradle.kts 中:

kotlin 复制代码
// 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:

kotlin 复制代码
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // setContent 是 Activity 的扩展函数,用于设置 Compose 界面
        setContent {
            // 这里写 Compose 代码
            Text(text = "Hello Compose!")
        }
    }
}

就这么简单。setContentactivity-compose 提供的扩展函数,它接受一个 @Composable 函数作为参数------所有 Compose 代码都在这里编写。

整个调用链的关系可以这样理解:

flowchart TB A[Activity.onCreate] --> B[setContent 扩展函数] B --> C[Composable 作用域建立] C --> D[Text
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 函数:

kotlin 复制代码
@Composable
fun Greeting(name: String) {
    Text(text = "Hello, $name!")
}

Composable 函数有两个硬性规则,刚接触时特别容易忽略:

  1. 函数名必须以大写字母开头。 这不是什么玄学------Compose 利用这个约定来区分"这是一个 Composable 界面组件"和"这是一个普通工具函数"。如果你用小写开头,编译器不会报错,但团队约定和 IDE 提示都会默认按大写走
  2. 只能在另一个 Composable 函数的作用域中调用 Composable 函数。 简单说,setContent { } 的花括号里、或者在某个 @Composable fun xxx() 里,才能调用别的 Composable。在普通 Kotlin 函数里直接调用 Text() 会编译报错

所以上面的 Activity 可以改写成:

kotlin 复制代码
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 包裹:

kotlin 复制代码
setContent {
    MaterialTheme {
        Greeting(name = "Compose")
    }
}

另外,Compose 提供了预览功能 ------用 @Preview 注解标注一个 Composable 函数,就可以在 Android Studio 的 Design 面板中实时看到效果,无需运行到真机:

kotlin 复制代码
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
    MaterialTheme {
        Greeting(name = "Compose")
    }
}

@Preview 只能标注不接收参数或参数有默认值的 Composable 函数,因为预览时无法传入参数。


四、基础控件详解

接下来逐个介绍最常用的 Compose 控件。每种控件我都会给出主要参数说明和完整的示例代码。

4.1 Text:文本显示

Text 是最基础的控件,用来显示文字:

kotlin 复制代码
@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 的按钮组件:

kotlin 复制代码
@Composable
fun ButtonExample() {
    Button(
        onClick = { /* 点击回调 */ },
        enabled = true,
        colors = ButtonDefaults.buttonColors(
            containerColor = Color.Blue,
            contentColor = Color.White
        )
    ) {
        // Button 的内容区域,可以放任何 Composable
        Text(text = "点击我")
    }
}

关键点:

  • Buttoncontent 参数(花括号内的内容)可以是 任意 Composable,不一定是 Text。你可以放 Image、Icon、Row 等
  • onClick 是必须传入的参数,定义了点击事件
  • enabled 控制按钮是否可点击

其他按钮变体:

kotlin 复制代码
// 描边按钮
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:文本输入框

文本输入框用来接收用户输入:

kotlin 复制代码
@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(状态):

你可能注意到了 remembermutableStateOf------这是 Compose 中管理状态的机制。简单来说:

  • mutableStateOf("") 创建了一个可观察的状态
  • remember 保证这个状态在重组(界面刷新)时不被重置
  • onValueChange 在每次输入变化时回调,我们把新值更新到状态中

关于 State 的详细讲解在第二篇文章中,这里先记住用法即可。

常用参数:

参数 说明
value 当前输入框的内容
onValueChange 内容变化时的回调
label 标签(显示在输入框上方或内部)
placeholder 占位提示文字
singleLine 是否单行输入
isError 是否显示错误状态
keyboardOptions 键盘配置(数字键盘、邮箱键盘等)
visualTransformation 视觉变换(如密码遮罩 PasswordVisualTransformation)

密码输入框示例:

kotlin 复制代码
@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 用来显示图片资源:

kotlin 复制代码
@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 模式:

kotlin 复制代码
ContentScale.Crop      // 裁剪居中(类似 XML 的 centerCrop)
ContentScale.Fit       // 等比缩放,可能留白(类似 fitCenter)
ContentScale.FillBounds // 拉伸填充(类似 fitXY)
ContentScale.Inside    // 缩小到容器内,不放大

painterResource() 会自动适配不同密度的图片资源,加载方式与 XML 中的 R.drawable.xxx 一致。 如果是从网络加载图片,需要使用 Coil 等三方库的 AsyncImage,这是后话。

4.5 Spacer:占位间距

Spacer 用来在布局中插入空白区域:

kotlin 复制代码
Spacer(modifier = Modifier.height(16.dp))  // 垂直间距
Spacer(modifier = Modifier.width(8.dp))    // 水平间距

五、Modifier 详解

Modifier 是 Compose 中最核心的概念之一。它用来装饰或增强一个 Composable 的外观和交互行为。

5.1 使用方式

几乎所有 Composable 都接收一个可选的 modifier 参数:

kotlin 复制代码
Text(
    text = "Hello",
    modifier = Modifier
        .padding(16.dp)          // 设置内边距
        .background(Color.Yellow) // 设置背景色
        .clickable { /* 点击 */ }  // 设置点击
        .fillMaxWidth()          // 填充最大宽度
)

5.2 链式调用与顺序

Modifier 通过链式调用组合多个行为,而且顺序很重要

kotlin 复制代码
// 顺序一:先 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)

六、实战:一个简单登录界面

把上面的知识串起来,写一个完整的登录界面:

kotlin 复制代码
@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 中:

kotlin 复制代码
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MaterialTheme {
                LoginScreen()
            }
        }
    }
}

效果说明:居中显示的"欢迎登录"标题,两个输入框,底部一个登录按钮。用户名或密码为空时按钮为禁用状态。

整个登录界面的组件树结构如下:

flowchart TB A[LoginScreen] --> B[Column
垂直居中] B --> C[Text
欢迎登录] B --> D[Spacer 32dp] B --> E[OutlinedTextField
用户名] B --> F[Spacer 16dp] B --> G[OutlinedTextField
密码] B --> H[Spacer 24dp] B --> I[Button
登录
enabled 受状态控制]

七、注意事项与小技巧

7.1 避免在 Composable 函数中写耗时操作

kotlin 复制代码
// ❌ 错误:在 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 参数尽量暴露出去

kotlin 复制代码
// ✅ 好的实践:将 modifier 作为参数并提供默认值
@Composable
fun MyCustomButton(
    text: String,
    onClick: () -> Unit,
    modifier: Modifier = Modifier
) {
    Button(
        onClick = onClick,
        modifier = modifier
    ) {
        Text(text = text)
    }
}

这样调用方可以自由定制按钮的样式和行为。

7.3 资源引用

在 Compose 中获取颜色、字符串、尺寸等资源:

kotlin 复制代码
// 字符串资源
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)

八、总结

这篇文章我们学习了:

  1. Compose 的核心概念:声明式 UI 与命令式 UI 的区别
  2. 环境搭建:Gradle 配置、BOM 的使用
  3. Composable 函数:基本规范和注意事项
  4. 基础控件:Text、Button、OutlinedTextField、Image、Spacer
  5. Modifier:链式调用、执行顺序、常用 Modifier 速查
  6. 实战:一个完整的登录界面

这些知识足以让你写出简单的 Compose 页面了。下一篇文章我们将进一步探讨 布局系统 (Column、Row、Box、LazyColumn 等)和 State 管理(remember、状态提升、StateFlow 收集),这些是写出复杂交互界面的基础。


如果你在搭建过程中遇到任何问题,欢迎在评论区留言交流。

相关推荐
StarShip7 小时前
Android 图形渲染流水线完整架构与执行流程分析
android
流年如夢8 小时前
类和对象(上)
android·java·开发语言
用户86022504674728 小时前
从入门到进阶的 React Native 实战指南
android·前端
沐言人生8 小时前
ReactNative 源码分析10——Native View创建流程createView
android·react native
问心无愧05138 小时前
ctf show web入门98
android·前端·笔记
李斯维8 小时前
Jetpack 生命周期组件 Lifecycle 的设计思想和使用
android·android studio·android jetpack
Mr YiRan9 小时前
Android构建优化:基于Git Diff+TaskGraph
android·git·elasticsearch
赏金术士9 小时前
第二章:Compose入门—声明式UI编程
android·ui·kotlin·compose
星间都市山脉9 小时前
Android 谷歌 VTS 完整测试
android