Jetpack Compose UI组件Mock回放实战 - 第1节

一、Jetpack Compose 是什么?先说说我的理解

Jetpack Compose,说白了就是 Android 官方推出的新一代 UI 框架。它用 Kotlin 的声明式语法替代了传统的 XML 布局。

我记得几年前刚开始接触 Android 开发时,写一个列表页要拖好几个 XML 文件,还要配适配器、ViewHolder,动不动就几百行代码。后来 Compose 一出来,我第一反应是:「这也太直接了吧?」直接把 UI 写在 Kotlin 代码里,什么布局、状态、事件全在一个文件里解决。

它的核心理念就两个:声明式和可组合。你想想看——你不再告诉系统「怎么画这个按钮」,而是直接说「我要一个按钮,文本是'点击我',颜色是蓝色」。剩下的事 Compose 自己搞定。

一句话总结:Compose = 用 Kotlin 函数描述 UI,系统自动帮你渲染和更新。

1.1 传统 View 系统 vs Compose

我刚开始用 Compose 时最大的感受就是——终于不用在 XML 和 Activity 之间反复横跳了。下面这张表可以帮你快速对比两者的差别:

维度 传统 View 系统 Jetpack Compose
布局方式 XML 文件 + 代码绑定 纯 Kotlin 函数
状态管理 findViewById + setText 等手动更新 State + 自动重组
复用机制 自定义 View / 适配器模式 @Composable 函数组合
学习成本 熟悉 XML + 生命周期 熟悉 Kotlin + 响应式思维
性能 依赖层级测量与绘制 跳过稳定组件,只重组变化部分
一点经验:如果你之前做过 Flutter 或 SwiftUI,Compose 的上手速度会非常快——因为它们都是声明式 UI。区别在于 Compose 用的是 Kotlin,语言风格更简洁。

二、环境搭建——我把坑都踩过了

搭建环境之前,我先说个前提:Compose 要求最低 Android API 21,Kotlin 版本 1.5+,而且必须用 Android Studio Arctic Fox 或更高版本。嗯,这些版本号记一下就行,真正麻烦的是 Gradle 配置里的版本对齐。

2.1 需要的工具

  • Android Studio:推荐 2023.1+ (Hedgehog) 或更新版本,内置 Compose 模版
  • JDK 17:Gradle 8.0 以上需要
  • Kotlin 1.9+:与 Compose BOM 版本匹配
  • Gradle 8.0+:建议使用 Gradle 8.4

2.2 创建项目——两分钟搞定

打开 Android Studio,点击「New Project」,选择「Empty Compose Activity」。你会看到自动生成的项目结构和默认的 MainActivity.kt。

// 默认的 Compose 入口长这样
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            // 这里写你的 UI 代码
            Text("Hello, Compose!")
        }
    }
}

我个人习惯每次新建项目后先检查两样东西:

  1. build.gradle.kts 中的 Compose BOM 版本
  2. Kotlin 编译器的 Compose 插件是否启用

2.3 核心配置详解(避坑指南)

我曾经因为 Compose 版本和 Kotlin 版本不匹配,卡了整整两个小时。编译报错莫名其妙,最后发现是 kotlinCompilerExtensionVersion 写错了。下面这段配置是我项目里用的,直接复制就能用,但注意升级版本时要同步改。

// 项目顶层 build.gradle.kts
plugins {
    id("com.android.application") version "8.2.0" apply false
    id("org.jetbrains.kotlin.android") version "1.9.21" apply false
}
// 模块级 build.gradle.kts
plugins {
    id("com.android.application")
    id("org.jetbrains.kotlin.android")
}

android {
    namespace = "com.example.myapp"
    compileSdk = 34

    defaultConfig {
        applicationId = "com.example.myapp"
        minSdk = 21
        targetSdk = 34
        versionCode = 1
        versionName = "1.0"
    }

    buildFeatures {
        compose = true
    }

    composeOptions {
        kotlinCompilerExtensionVersion = "1.5.7"
    }
}

dependencies {
    // Compose BOM —— 帮你统一版本号
    val composeBom = platform("androidx.compose:compose-bom:2024.01.00")
    implementation(composeBom)

    implementation("androidx.compose.ui:ui")
    implementation("androidx.compose.ui:ui-tooling-preview")
    implementation("androidx.compose.material3:material3")
    debugImplementation("androidx.compose.ui:ui-tooling")
}
注意!kotlinCompilerExtensionVersion 必须和 Kotlin 版本严格对齐。比如 Kotlin 1.9.21 对应 Compose Compiler 1.5.7。如果你用了 Kotlin 1.9.22 却还写 1.5.7,编译直接报“Unsupported Kotlin version”。我建议每次升级 Kotlin 之后,去 官方兼容性表 查一下对应版本。

三、理解核心概念——从 Hello World 到第一个组件

环境配好了,我们来写第一个真正的 Compose 页面。别小看这个例子,它包含了所有关键概念:可组合函数、修饰符、状态和重组。

@Composable
fun Greeting(name: String) {
    var count by remember { mutableStateOf(0) }

    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(
            text = "Hello, $name!",
            fontSize = 24.sp,
            color = Color.Blue
        )

        Spacer(modifier = Modifier.height(16.dp))

        Button(onClick = { count++ }) {
            Text("点击次数:$count")
        }
    }
}

这段代码里出现了几个新东西:

  • @Composable —— 告诉编译器这是个可组合函数
  • remember + mutableStateOf —— 声明可观察状态,State 变了 UI 自动重组
  • Modifier —— 链式调用的修饰符,控制尺寸、间距、点击事件等
  • Column / Button / Text —— 内建组件,像搭积木一样嵌套
一个小技巧:刚开始学 Compose 时,你可能会对 Modifier 的顺序很困惑。记住:先定大小(fillMaxSize、size、width),再定内边距(padding),最后定对齐(align、center)。顺序错了效果会不一样,我亲测过。

四、一张图看懂 Compose 的工作流程

Jetpack Compose 核心工作流程 可组合函数 @Composable fun State 状态 mutableStateOf / remember 组合器 Column / Row / Box 修饰符链 Modifier.xxx().yyy() 重组 状态变化 → 自动刷新 ⚠️ 要点 只有 State 变化 生效的部分才会重组 不会整页重绘 箭头方向:定义 → 组合 → 修饰 → 响应状态变化 → 重组
流程图解读:你写一个可组合函数,里面用 Column 等组合器安排布局,再用 Modifier 调整样式;State 就像UI的「数据源」,当它变化时,Compose 只重新执行那些依赖了变化状态的函数——这就是「重组」。整个过程由 Compose 运行时自动管理,你只管描述结果。

五、第一个实战练习——写一个带交互的卡片

光说不练假把式。我们来写一个稍微真实点的组件:一个可展开的详情卡片。它在项目里很常见——比如展示商品信息,点击下拉查看更多。

@Composable
fun ExpandableCard(title: String, description: String) {
    var expanded by remember { mutableStateOf(false) }

    Card(
        modifier = Modifier
            .fillMaxWidth()
            .padding(12.dp)
            .clickable { expanded = !expanded }
    ) {
        Column(modifier = Modifier.padding(16.dp)) {
            Text(text = title, fontWeight = FontWeight.Bold, fontSize = 18.sp)
            
            AnimatedVisibility(visible = expanded) {
                Text(
                    text = description,
                    modifier = Modifier.padding(top = 8.dp),
                    color = Color.Gray
                )
            }
        }
    }
}

这里我用了 AnimatedVisibility,它是 Compose 内置的动画组件——展开和收起自带淡入淡出效果。你想想看,传统 View 系统要实现这种效果得写多少代码?属性动画、ViewTreeObserver、布局刷新……在 Compose 里一行动画声明就搞定了。

我的习惯:每次写新的可组合函数,我会先把「静态布局」写出来,确保 UI 显示正确,然后再加状态和交互。这样调试起来思路清晰,不容易被重组搞晕。

六、关于预览——你可能没注意到的细节

Compose 提供 @Preview 注解,可以在 Android Studio 的 Design 面板中直接看到组件效果,不用跑模拟器。

@Preview(showBackground = true, name = "默认卡片")
@Composable
fun PreviewExpandableCard() {
    ExpandableCard(
        title = "Android 12",
        description = "Material You 动态取色,更流畅的动画"
    )
}

预览功能对快速迭代 UI 帮助巨大。我以前写 XML 时改一个间距就要重新 build 跑模拟器,等个几十秒。现在改完 Compose 代码,Preview 几乎实时刷新。

但是注意:@Preview 里的代码不能有复杂的业务逻辑,比如网络请求、数据库操作。它只适合展示纯 UI 状态。我曾经在 preview 里放了一个 viewModel 调用,结果每次预览都报错——后来改成了纯数据传参才解决。

七、本章小结

这一章我们聊了 Compose 的定位、搭建环境、核心概念,以及第一个实战组件。说几点我个人很深的体会:

  • 环境搭建最关键的坑是版本匹配,尤其是 kotlinCompilerExtensionVersion
  • 声明式 UI 思维需要适应——别总想着「怎么改」,要想「状态变了之后 UI 应该长什么样」
  • Preview 非常好用,但别放复杂逻辑