第1课:Compose基础入门
🎯 本节课目标
- 理解什么是Compose
- 学会写第一个Compose函数
- 理解@Composable注解
- 理解Modifier的作用
📖 第一部分:什么是Compose?
传统方式(XML布局)vs Compose方式
传统方式(XML + Java/Kotlin):
xml
<!-- activity_main.xml -->
<LinearLayout>
<TextView android:text="Hello" />
<Button android:text="Click Me" />
</LinearLayout>
Compose方式(纯Kotlin代码):
kotlin
@Composable
fun MainScreen() {
Column {
Text("Hello")
Button(onClick = { }) {
Text("Click Me")
}
}
}
关键区别:
- ✅ 代码即UI,不需要XML文件
- ✅ 类型安全,编译时检查
- ✅ 函数式编程,更简洁
- ✅ 状态变化时自动更新UI
🔍 第二部分:看一个真实的例子
让我们看项目中最简单的一个Screen:
kotlin:30:85:app/src/main/java/com/volvocars/telephony/china/ui/calllog/CallLogScreen.kt
@Composable
fun CallLogScreen(
modifier: Modifier = Modifier,
callLogVM: CallLogViewModel = koinViewModel(),
contactsVM: ContactsViewModel = koinViewModel(),
callVM: CallViewModel = koinViewModel()
) {
val uiState by callLogVM.uiState.collectAsStateWithLifecycle()
LaunchedEffect(Unit) {
callLogScreen.sendIntent(CallLogIntent.FetchCallLog)
contactsVM.sendIntent(ContactsIntent.FetchContacts)
}
Box(
modifier = modifier,
contentAlignment = Alignment.TopStart
) {
when (uiState.loadState) {
is LoadState.Idle -> {
}
is LoadState.Loading -> {
Loading(modifier = Modifier.fillMaxSize(), text = stringResource(id = R.string.sync_data))
}
is LoadState.Empty -> {
DefaultStatusPageScreen(
modifier = Modifier.fillMaxSize(),
status = DefaultPageScreenStatus.NoCallLog,
btnClick = {
callLogVM.sendIntent(CallLogIntent.FetchCallLog)
}
)
}
is LoadState.LoadSuccess -> {
LazyColumn(
modifier = Modifier.padding(start = appDimens.dev.dp24 + appDimens.spacing.spacing4xLarge),
verticalArrangement = Arrangement.spacedBy(appDimens.spacing.spacingXSmall)
) {
items(uiState.data ?: emptyList()) { data ->
CallContactListItem(
callContactEntry = data,
onClick = {
callVM.sendIntent(CallIntent.PlaceCall(data.phoneNumbers()?.firstOrNull()?.number))
}
)
}
}
}
is LoadState.LoadError -> {
}
}
}
}
🎓 第三部分:逐步讲解
1. @Composable 注解
kotlin
@Composable
fun CallLogScreen(...)
作用:
- 告诉编译器:这是一个Compose函数
- 这个函数可以在
setContent { }中调用 - 可以调用其他
@Composable函数
规则:
@Composable函数只能在其他@Composable函数中调用- 不能在普通函数中调用
kotlin
// ✅ 正确
@Composable
fun Parent() {
Child() // 可以调用
}
// ❌ 错误
fun normalFunction() {
Child() // 不能调用!
}
2. 函数参数
kotlin
fun CallLogScreen(
modifier: Modifier = Modifier, // 样式参数
callLogVM: CallLogViewModel = koinViewModel() // ViewModel(暂时忽略)
)
modifier参数:
- 几乎所有Compose组件都有
modifier参数 - 用于控制样式、大小、位置等
- 默认值是
Modifier(无效果)
默认参数:
= Modifier:调用时可以不传= koinViewModel():会自动获取ViewModel(后面讲)
3. 第一个布局组件:Box
kotlin
Box(
modifier = modifier,
contentAlignment = Alignment.TopStart
) {
// 子组件
}
Box的作用:
- 层叠布局(类似FrameLayout)
- 可以叠加多个组件
contentAlignment:控制子组件对齐方式
对齐方式:
Alignment.TopStart:左上角Alignment.Center:居中Alignment.BottomEnd:右下角- 等等...
4. 条件渲染:when表达式
kotlin
when (uiState.loadState) {
is LoadState.Loading -> LoadingScreen()
is LoadState.LoadSuccess -> ContentScreen()
is LoadState.Empty -> EmptyScreen()
is LoadState.LoadError -> ErrorScreen()
}
作用:
- 根据状态显示不同的UI
- 类似if-else,但更清晰
is关键字:类型检查
这是Compose的核心思想:
- 状态驱动UI
- 状态改变 → UI自动更新
💡 第四部分:动手实践
任务1:写你的第一个Compose函数
创建一个新文件,写一个最简单的Screen:
kotlin
@Composable
fun MyFirstScreen() {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text("Hello Compose!")
}
}
解释:
Modifier.fillMaxSize():填满整个屏幕Alignment.Center:居中显示Text("Hello Compose!"):显示文本
任务2:尝试不同的对齐方式
修改contentAlignment,看看效果:
kotlin
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.TopStart // 试试改成 TopCenter, BottomEnd 等
) {
Text("Hello Compose!")
}
任务3:添加多个组件
kotlin
@Composable
fun MyFirstScreen() {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Column { // Column:垂直排列
Text("第一行")
Text("第二行")
Text("第三行")
}
}
}
Column的作用:
- 垂直排列子组件
- 类似LinearLayout(vertical)
🎯 第五部分:Modifier详解
什么是Modifier?
Modifier = 样式和布局的修饰符
kotlin
Text(
text = "Hello",
modifier = Modifier
.padding(16.dp) // 内边距
.background(Color.Red) // 背景色
.fillMaxWidth() // 填满宽度
)
常用Modifier(先记住这几个)
| Modifier | 作用 | 示例 |
|---|---|---|
.fillMaxSize() |
填满父容器 | Modifier.fillMaxSize() |
.fillMaxWidth() |
填满宽度 | Modifier.fillMaxWidth() |
.size(100.dp) |
固定大小 | Modifier.size(100.dp) |
.padding(16.dp) |
内边距 | Modifier.padding(16.dp) |
.background(Color.Red) |
背景色 | Modifier.background(Color.Red) |
.clickable { } |
点击事件 | Modifier.clickable { onClick() } |
Modifier的链式调用
kotlin
Modifier
.fillMaxWidth() // 先填满宽度
.padding(16.dp) // 再加内边距
.background(Color.White) // 再设置背景
.clickable { } // 最后加点击事件
重要:顺序很重要!
- 先设置的会影响后设置的
- 通常顺序:大小 → 间距 → 样式 → 事件
实践:给Text添加样式
kotlin
@Composable
fun MyFirstScreen() {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text(
text = "Hello Compose!",
modifier = Modifier
.padding(20.dp)
.background(Color.Blue)
.padding(10.dp) // 注意:这个padding在background外面
)
}
}
观察:
- 背景色在哪里?
- padding在哪里?
- 试试调整顺序看看效果
📚 第六部分:常用基础组件
Text - 文本
kotlin
Text(
text = "Hello World",
color = Color.Black,
fontSize = 16.sp
)
Button - 按钮
kotlin
Button(onClick = {
// 点击事件
}) {
Text("点击我")
}
Column - 垂直布局
kotlin
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally // 水平居中
) {
Text("第一行")
Text("第二行")
}
Row - 水平布局
kotlin
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween // 两端对齐
) {
Text("左侧")
Text("右侧")
}
✍️ 第七部分:综合练习
练习:创建一个简单的登录界面
kotlin
@Composable
fun LoginScreen() {
Column(
modifier = Modifier
.fillMaxSize()
.padding(32.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(
text = "登录",
fontSize = 24.sp
)
Spacer(modifier = Modifier.height(32.dp)) // 间距
Text(
text = "用户名",
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(16.dp))
Text(
text = "密码",
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(32.dp))
Button(
onClick = { /* 登录 */ },
modifier = Modifier.fillMaxWidth()
) {
Text("登录")
}
}
}
学习点:
- Column垂直布局
- modifier链式调用
- Spacer添加间距
- fillMaxWidth()的使用
🎯 本节课总结
核心概念
- @Composable:标记Compose函数
- Modifier:样式和布局修饰符
- Box:层叠布局
- Column:垂直布局
- Row:水平布局
关键点
- Compose是声明式UI:描述"是什么",而不是"怎么做"
- 状态驱动UI:状态改变,UI自动更新
- Modifier链式调用:顺序很重要