第二章:Compose入门—声明式UI编程

第二章:Compose 入门 --- 声明式 UI 编程

Compose 的核心理念:用 Kotlin 代码声明 UI,而不是用 XML 布局文件。


2.1 传统 View 系统 vs Compose

对比项 传统 View 系统 Jetpack Compose
UI 描述 XML 布局文件 Kotlin 代码
状态更新 findViewById + 手动修改 状态驱动自动重组
组件创建 继承 ViewGroup 调用 Composable 函数
预览 XML 预览编辑器 @Preview Composable
声明方式 指令式 声明式

传统方式:

xml 复制代码
<!-- activity_main.xml -->
<LinearLayout>
    <TextView android:id="@+id/tv_title"/>
    <Button android:id="@+id/btn_submit"/>
</LinearLayout>
kotlin 复制代码
// MainActivity.kt
tv_title.text = "Hello"
btn_submit.setOnClickListener { ... }

Compose 方式:

kotlin 复制代码
@Composable
fun GreetingPage() {
    var text by remember { mutableStateOf("Hello") }
    
    Column {
        Text(text = text)
        Button(onClick = { text = "World" }) {
            Text("Click me")
        }
    }
}

2.2 Composable 函数

Compose 的 UI 构建块是 @Composable 函数,简称 Composable。

kotlin 复制代码
@Composable
fun ArticleItem(title: String, description: String?, onClick: () -> Unit) {
    Card(
        modifier = Modifier
            .fillMaxWidth()
            .padding(12.dp)
            .clickable(onClick = onClick),
    ) {
        Column {
            ArticleImage(imageUrl = thumbnail.orEmpty())
            Text(text = title, fontWeight = FontWeight.Bold)
            Text(text = description ?: "暂无描述")
        }
    }
}

要点:

  • 函数标记 @Composable,告诉编译器这是 UI 构建函数
  • Composable 函数可以嵌套调用,形成 UI 树
  • 所有 UI 状态通过参数传入或内部 state 管理

2.3 Modifier 修饰符

Modifier 用于配置 Composable 的布局、样式、交互:

kotlin 复制代码
Text(
    text = "Hello",
    modifier = Modifier
        .fillMaxWidth()        // 宽度撑满
        .padding(16.dp)        // 内边距
        .clickable(onClick = {}), // 可点击
    fontWeight = FontWeight.Bold,
    color = MaterialTheme.colorScheme.primary,
)

常用 Modifier:

Modifier 作用
fillMaxWidth() 宽度撑满父布局
padding(16.dp) 设置内边距
.clickable { } 添加点击事件
Modifier.size(48.dp) 固定尺寸
.clip(CircleShape) 裁剪形状

2.4 状态管理

Compose 是响应式的,当状态变化时 UI 自动重组。

kotlin 复制代码
@Composable
fun SearchBar() {
    var searchText by remember { mutableStateOf("") }
    
    OutlinedTextField(
        value = searchText,
        onValueChange = { searchText = it },  // 状态更新 → UI 重组
        label = { Text("搜索内容") },
    )
}

关键函数:

  • mutableStateOf(initial) --- 创建可观察状态
  • remember { } --- 在重组时保持状态不丢失
  • collectAsState() --- 将 StateFlow 转为 Compose 状态

2.5 Material3 组件

项目使用 Material3 设计语言:

kotlin 复制代码
Scaffold(
    topBar = {
        TopAppBar(
            title = { Text("Compose 入门项目") },
            actions = {
                IconButton(onClick = { /* 跳转个人中心 */ }) {
                    Icon(Icons.Default.Person, contentDescription = "个人中心")
                }
            }
        )
    }
) { padding ->
    // 页面内容,padding 是顶部栏的高度
    Box(modifier = Modifier.padding(padding)) {
        // ...
    }
}

常用 Material3 组件:

  • Scaffold --- 页面脚手架,提供 TopAppBar/BottomBar 等
  • Card --- 卡片容器
  • Button/TextButton --- 按钮
  • OutlinedTextField --- 输入框
  • LazyColumn/LazyRow --- 高性能列表(替代 RecyclerView)
  • CircularProgressIndicator --- 加载中指示器

2.6 列表渲染:LazyColumn

传统 RecyclerView 替代方案:

kotlin 复制代码
LazyColumn {
    items(
        items = articles,
        key = { it.id },  // 高效重组的关键
    ) { item ->
        ArticleItem(
            title = item.title,
            description = item.description,
            onClick = { onArticleClick(item) }
        )
    }
}

优势:

  • 无需 Adapter/ViewHolder
  • key 参数确保高效更新
  • 支持 itemsIndexed 获取索引

2.7 预览功能

Android Studio 支持 @Preview 实时预览:

kotlin 复制代码
@Preview(showBackground = true, name = "文章条目")
@Composable
fun ArticleItemPreview() {
    MyFirstComposeTheme {
        Surface(modifier = Modifier.fillMaxSize()) {
            ArticleItem(
                title = "Jetpack Compose 入门",
                description = "学习声明式 UI 编程",
                thumbnail = null,
                onClick = {},
            )
        }
    }
}

预览文件通常命名为 XxxPagePreview.kt,与页面分开存放。


2.8 总结

  • Compose 用 Kotlin 代码声明 UI,无需 XML
  • 状态变化自动触发 UI 重组
  • Modifier 配置组件属性,链式调用
  • LazyColumn 替代 RecyclerView,更简洁
  • @Preview 支持实时预览加速开发

上一章:第一章:项目概述与环境搭建 下一章:第三章:MVVM 架构与 ViewModel

相关推荐
johnny23317 分钟前
UI新革命?GenUI、WanDB-OpenUI、thesysdev-OpenUI、A2UI、AG-UI、MCP-UI
ui
天天进步201510 小时前
UI-TARS 源码解析 #10:parse_action 源码解析:如何用 AST 安全解析模型生成的函数调用?
安全·ui
HLC++12 小时前
Linux的进程间通信
android·linux·服务器
爱笑鱼16 小时前
Binder(二):AIDL 生成的 Proxy、Stub 和 Parcel 到底在做什么?
android
爱笑鱼16 小时前
Binder(一):一次方法调用,究竟怎样跨进程执行?
android
btown17 小时前
Kotlin 版 MyBatis-Plus 查询优雅解决方案
kotlin
壮哥_icon17 小时前
【Android 系统开发】使用 BAT 脚本高效自动化管理 /system/priv-app/ 系统应用(安装与卸载)
android·运维·自动化
用户693717500138418 小时前
Claude Code终端日志Token占用实测:一个过滤器砍掉60%-90%
android·前端·后端
FuckPatience18 小时前
Telerik UI for WPF 值不能为null。参数名:key
ui·wpf
蝉蜕日记19 小时前
AccumuPDF高级版 v2.57 | 视图文转换PDF,合并分割压缩
android·智能手机·pdf·生活·软件需求