初步熟悉Jetpack Compose。学习并了解可组合函数、基本布局和状态、Material Design、列表和动画。
更多更全布局组件以及各类API参见:Jetpack Compose 使用入门
一、可组合函数(Composable Functions)
1.1、基本概念
- @Composable 注解:标记函数为 UI 组件
- 声明式 UI:通过函数描述界面,而非 XML
- 重组(Recomposition) :当输入参数变化时自动刷新 UI
1.2、示例:创建简单组件
@Composable
fun Greeting(name: String) {
Text(text = "Hello, $name!") // 使用 Material Design 的 Text 组件
}
// 调用
Greeting(name = "Android")
1.3、参数与复用
@Composable
fun IconButton(icon: ImageVector, onClick: () -> Unit) {
IconButton(onClick = onClick) {
Icon(imageVector = icon, contentDescription = null)
}
}
// 调用
IconButton(icon = Icons.Default.Favorite, onClick = { /* 处理点击 */ })
二、基本布局与状态管理
2.1、常用布局
| 布局组件 | 描述 | 示例 |
|---|---|---|
Column | 垂直排列子元素 | Column { Text("A"); Text("B") } |
Row | 水平排列子元素 | Row { Text("A"); Text("B") } |
Box | 叠加子元素 | Box { Image(); FloatingActionButton() } |
Spacer | 填充空白 | Spacer(modifier = Modifier.width(16.dp)) |
2.2、状态管理
@Composable
fun Counter() {
var count by remember { mutableStateOf(0) } // 状态变量
Column {
Text("Count: $count")
Button(onClick = { count++ }) {
Text("Increment")
}
}
}
2.3、状态提升(State Hoisting)
@Composable
fun HoistedCounter(count: Int, onCountChange: (Int) -> Unit) {
Column {
Text("Count: $count")
Button(onClick = { onCountChange(count + 1) }) {
Text("Increment")
}
}
}
// 父组件管理状态
@Composable
fun Parent() {
var count by remember { mutableStateOf(0) }
HoistedCounter(count = count, onCountChange = { newCount -> count = newCount })
}
三、Material Design 组件
3.1、常用组件
@Composable
fun MaterialComponents() {
Column(modifier = Modifier.padding(16.dp)) {
// 按钮
Button(onClick = {}) { Text("Button") }
// 输入框
var text by remember { mutableStateOf("") }
TextField(value = text, onValueChange = { text = it }, label = { Text("Input") })
// 卡片
Card(elevation = 4.dp) {
Column(modifier = Modifier.padding(16.dp)) {
Text("Card Title")
Text("Card Content")
}
}
}
}
3.2、主题定制
// 在 Activity 的 setContent 前设置
MaterialTheme(
colors = darkColors(primary = Color.Blue), // 自定义颜色
typography = Typography(body1 = TextStyle(fontFamily = FontFamily.Monospace)), // 字体
shapes = Shapes(small = RoundedCornerShape(8.dp)) // 形状
) {
// 组件树
}
四、列表处理(LazyColumn/LazyRow)
4.1、基本列表
@Composable
fun SimpleList(items: List<String>) {
LazyColumn {
items(items) { item ->
Text(text = item, modifier = Modifier.padding(16.dp))
}
}
}
4.2、复杂列表(带点击事件)
data class User(val id: Int, val name: String)
@Composable
fun UserList(users: List<User>, onItemClick: (User) -> Unit) {
LazyColumn {
items(users, key = { it.id }) { user ->
Card(
modifier = Modifier
.fillMaxWidth()
.clickable { onItemClick(user) }
.padding(8.dp)
) {
Text(text = user.name, modifier = Modifier.padding(16.dp))
}
}
}
}
五、动画(Animations)
5.1、简单动画
@Composable
fun AnimatedButton() {
var enabled by remember { mutableStateOf(true) }
val backgroundColor by animateColorAsState(if (enabled) Color.Green else Color.Red)
Button(
onClick = { enabled = !enabled },
colors = ButtonDefaults.buttonColors(backgroundColor = backgroundColor)
) {
Text(if (enabled) "Enabled" else "Disabled")
}
}
5.2、布局动画
@Composable
fun AnimatedVisibilityDemo() {
var visible by remember { mutableStateOf(true) }
Column {
AnimatedVisibility(visible = visible) {
Text("Hello, I can fade in/out!")
}
Button(onClick = { visible = !visible }) {
Text("Toggle Visibility")
}
}
}
5.3、过渡动画
@Composable
fun TransitionDemo() {
var isExpanded by remember { mutableStateOf(false) }
val transition = updateTransition(targetState = isExpanded, label = "expandTransition")
val rotation by transition.animateFloat(label = "rotation") { state ->
if (state) 180f else 0f
}
IconButton(onClick = { isExpanded = !isExpanded }) {
Icon(
imageVector = Icons.Default.Expand,
contentDescription = null,
modifier = Modifier.rotate(rotation)
)
}
}
六、综合案例:示例应用
data class TodoItem(val id: Int, val task: String, var completed: Boolean)
@Composable
fun TodoApp() {
var todos by remember { mutableStateOf(emptyList<TodoItem>()) }
var newTask by remember { mutableStateOf("") }
Column(modifier = Modifier.padding(16.dp)) {
// 输入框
TextField(
value = newTask,
onValueChange = { newTask = it },
label = { Text("New Task") }
)
// 添加按钮
Button(onClick = {
if (newTask.isNotBlank()) {
todos = todos + TodoItem(todos.size + 1, newTask, false)
newTask = ""
}
}) {
Text("Add Task")
}
// 列表
LazyColumn {
items(todos, key = { it.id }) { todo ->
Row(verticalAlignment = Alignment.CenterVertically) {
Checkbox(
checked = todo.completed,
onCheckedChange = { checked ->
todos = todos.map {
if (it.id == todo.id) it.copy(completed = checked) else it
}
}
)
Text(
text = todo.task,
modifier = Modifier.padding(8.dp),
style = if (todo.completed) LocalTextStyle.current.copy(
color = Color.Gray,
textDecoration = TextDecoration.LineThrough
) else LocalTextStyle.current
)
}
}
}
}
}
七、学习资源
- 官方文档:Jetpack Compose
- 代码实验室:Compose Basics
- GitHub 示例:Compose Samples
- GitHub 示例:Now in Android
通过以上教程,你可以逐步掌握 Compose 的核心概念,并构建出美观且功能完善的 Android 应用!