SwiftUI 快速上手:从 UIKit 到声明式 UI
掌握 SwiftUI 的 View 协议、@State/@Binding 状态体系、布局三件套和 MVVM 架构——适合有 iOS 基础想转型的开发者。
Android 的传统 UI 方案(XML Layout + findViewById / ViewBinding + 命令式更新)有三个根本问题:
setText、setVisibility,极易不一致RecyclerView 的 Adapter 样板代码多得离谱Jetpack Compose 的答案是声明式 UI:你描述 UI 应该长什么样,框架负责把它渲染出来并自动更新。
// 不需要 XML!一个函数就是一段 UI
@Composable
fun Greeting(name: String) {
Text(
text = "こんにちは、$name さん!",
style = MaterialTheme.typography.headlineMedium
)
}
@Composable 注解告诉编译器:「这个函数要把数据转换成 UI」。它有以下特性:
@Composable
fun NinjaCard(ninja: Ninja) {
Card(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
elevation = CardDefaults.cardElevation(defaultElevation = 4.dp)
) {
Column(modifier = Modifier.padding(16.dp)) {
Text(text = ninja.name, style = MaterialTheme.typography.titleLarge)
Spacer(modifier = Modifier.height(4.dp))
Text(text = "${ninja.rank} · ${ninja.village}", color = MaterialTheme.colorScheme.secondary)
}
}
}
如果说 @Composable 函数是骨架,那 Modifier 就是血肉。它控制组件的外观、布局、行为和交互:
@Composable
fun ModifierDemo() {
Box(
modifier = Modifier
.size(100.dp) // 尺寸
.background(Color.Red) // 背景
.clip(CircleShape) // 裁剪
.border(2.dp, Color.White) // 边框
.clickable { /* 点击 */ } // 交互
.padding(8.dp) // 内边距
)
}
⚠️ Modifier 的顺序很重要! 链式调用是从上到下依次应用的。比如先
padding再background,背景不包括 padding 区域;反过来,先background再padding,padding 区域也有背景色。
常用 Modifier 速查:
| Modifier | 作用 |
|---|---|
size(width, height) | 固定尺寸 |
fillMaxWidth/Height/Size() | 撑满父容器 |
padding(start, top, ...) | 内边距 |
background(color, shape) | 背景色 |
clip(shape) | 裁剪形状 |
border(width, color, shape) | 边框 |
clickable { } | 点击事件 |
alpha(0.5f) | 透明度 |
shadow(elevation, shape) | 阴影 |
声明式 UI 的核心循环是:State 变化 → Recomposition → UI 更新。
@Composable
fun Counter() {
// 记住跨 recomposition 的状态
var count by remember { mutableStateOf(0) }
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text(text = "カウント: $count", style = MaterialTheme.typography.headlineSmall)
Spacer(modifier = Modifier.height(8.dp))
Button(onClick = { count++ }) {
Text("+1")
}
}
}
几个关键概念:
mutableStateOf — 创建可观察的状态对象。值改变时,所有读取它的 Composable 自动重组remember — 在 recomposition 期间保留值。没有它,每次重组 count 都会重置为 0by 委托 — 语法糖,相当于 count.value++,让代码更清爽@Composable
fun RememberLifecycle() {
var count = remember { mutableStateOf(0) } // 组件离开组合树时被遗忘
// 需要一个 key 来"记住版本"
val user by remember(userId) { mutableStateOf(loadUser(userId)) }
// key(userId) 改变时重新初始化
}
当 Composable 从组合树中被移除(比如导航到另一页),remember 存储的值就丢失了。要跨导航保留状态,可以用 rememberSaveable —— 它会在配置变更(旋转屏幕)后恢复。
Compose 里没有 LinearLayout、RelativeLayout、FrameLayout。一切都简化为几个核心布局:
// Column = 垂直排列
@Composable
fun ColumnExample() {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center, // 主轴(垂直)对齐
horizontalAlignment = Alignment.CenterHorizontally // 交叉轴对齐
) {
Text("上")
Spacer(modifier = Modifier.height(16.dp))
Text("中")
Spacer(modifier = Modifier.height(16.dp))
Text("下")
}
}
// Row = 水平排列
@Composable
fun RowExample() {
Row(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Icon(Icons.Default.Favorite, contentDescription = null)
Text("居中")
Button(onClick = {}) { Text("右对齐") }
}
}
// Box = 层叠(类似 FrameLayout)
@Composable
fun BoxExample() {
Box(contentAlignment = Alignment.Center) {
Image(painter = painterResource(R.drawable.bg), contentDescription = null)
Text("在图片上方")
}
}
@Composable
fun MissionList(missions: List<Mission>) {
LazyColumn {
items(missions, key = { it.id }) { mission ->
MissionCard(mission)
}
// 列表为空时
if (missions.isEmpty()) {
item {
Text("暂无任务", modifier = Modifier.padding(32.dp))
}
}
}
}
LazyColumn 只组合屏幕可见的 item,滚出屏幕的 item 会被回收。要传 key,否则 item 错位是迟早的事。
// 定义颜色
private val DarkColors = darkColorScheme(
primary = Color(0xFFFF6B1A), // 火影橙
secondary = Color(0xFFE8B830), // 金色
background = Color(0xFF0D0A08),
surface = Color(0xFF181310)
)
// 定义主题
@Composable
fun NinjaTheme(content: @Composable () -> Unit) {
MaterialTheme(
colorScheme = DarkColors,
typography = Typography, // 自定义字体
content = content
)
}
| 特性 | Jetpack Compose | SwiftUI | Vue 3 |
|---|---|---|---|
| 语言 | Kotlin | Swift | TypeScript |
| 声明方式 | @Composable fun | struct View | <template> + Composition API |
| 状态管理 | mutableStateOf + remember | @State / @StateObject | ref / reactive |
| 布局 | Column / Row / Box | VStack / HStack / ZStack | CSS Flexbox / Grid |
| 响应式模型 | 重组(Recomposition) | 差异更新 | Proxy 依赖追踪 |
🎯 三大平台的声明式 UI 框架设计理念惊人地相似——都是状态驱动 UI 更新。学会一个,另外两个的思维模型可以直接迁移。
Jetpack Compose 不是 XML Layout 的「语法糖版本」,它是安卓 UI 开发的范式转变。声明式 UI 让你用更少的代码实现更一致、更可预测的界面。如果你之前写惯了 XML + Adapter,最初几周会有些不适——特别是调试重组和性能优化——但一旦跨过那个坎,你就回不去了。
掌握 SwiftUI 的 View 协议、@State/@Binding 状态体系、布局三件套和 MVVM 架构——适合有 iOS 基础想转型的开发者。
记录我使用 Nuxt 3 + Tailwind CSS + Nuxt Content 搭建个人博客的完整过程,涵盖项目初始化、文件路由、内容管理和暗色模式配置。
深入理解 React Hooks 的心智模型——闭包陷阱、依赖数组、自定义 Hook,以及和 Vue Composables 的异同对比。