Jetpack Compose Android 声明式 UI
kotlin android { buildFeatures { compose = true } composeOptions { kotlinCompilerExtensionVersion = "1.5.4" // 根据最新版本调整 } }
dependencies { implementation(platform("androidx.compose:compose-bom:2024.01.00")) implementation("androidx.compose.ui:ui") implementation("androidx.compose.material3:material3") implementation("androidx.compose.ui:ui-tooling-preview") debugImplementation("androidx.compose.ui:ui-tooling") }
3. 同步项目,环境即准备完毕。
## 第一个可组合函数
任何一个被 `@Composable` 注解标记的函数都可以生成界面片段。让我们从经典的“Hello World”开始。
```kotlin
@Composable
fun Greeting(name: String) {
Text(text = "Hello $name!")
}
在 Activity 中使用:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Greeting("Compose")
}
}
}
setContent 块内就是一个 Compose 作用域,你可以直接调用任何可组合函数。
基础组件
Compose 提供了一系列内置的可组合项,帮助你快速搭建界面。
Text
显示文本,支持设置颜色、字号、字重等。
Text(
text = "欢迎学习 Compose",
color = Color.Blue,
fontSize = 20.sp,
fontWeight = FontWeight.Bold
)
Button
按钮组件,用 onClick 处理点击事件。
Button(onClick = { /* 处理点击 */ }) {
Text("点击我")
}
Image
显示本地或网络图片资源。
Image(
painter = painterResource(id = R.drawable.ic_launcher),
contentDescription = "图标"
)
TextField
文本输入框,需要维护一个状态变量来存储输入值。
var text by remember { mutableStateOf("") }
TextField(
value = text,
onValueChange = { text = it },
label = { Text("输入内容") }
)
其他常用组件
Surface:提供背景和边框的容器Checkbox:复选框RadioButton:单选框Slider:滑动条
布局方式
Compose 采用“容器 + 内容”的模式进行布局,所有布局组件自身也是可组合函数。
Column(垂直排列)
Column {
Text("第一行")
Text("第二行")
}
Row(水平排列)
Row {
Text("左")
Text("右")
}
Box(层叠布局)
允许子元素重叠放置,可通过 alignment 控制定位。
Box {
Image(...)
Text("叠加文字", modifier = Modifier.align(Alignment.Center))
}
使用 Modifier 调整布局
Modifier 是 Compose 的万能修饰符,可控制尺寸、间距、对齐、背景等。
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text("居中的文本")
}
常用 Modifier 扩展:
fillMaxWidth()/fillMaxSize()size(width, height)padding(all)/padding(horizontal, vertical)background(color, shape)border(width, color, shape)
状态管理与重组
在 Compose 中,当状态发生变化时,所有读取该状态的可组合函数会自动重新执行(重组),生成新的 UI。
使用 remember 与 mutableStateOf
@Composable
fun Counter() {
var count by remember { mutableStateOf(0) }
Column {
Text("Count: $count")
Button(onClick = { count++ }) {
Text("增加")
}
}
}
mutableStateOf创建一个可观察的状态对象,值变化时触发重组remember确保在重组期间状态不会被重置
状态提升
将状态移动到更高的可组合函数中,实现状态共享和复用。
@Composable
fun Counter(count: Int, onIncrement: () -> Unit) {
Column {
Text("Count: $count")
Button(onClick = onIncrement) {
Text("增加")
}
}
}
父级持有状态并向下传递,这种方式被称为单向数据流。
Material Design 3 主题
Compose 原生集成了 Material 3,可通过 MaterialTheme 访问颜色、字体、形状系统。
自定义主题
在 Theme.kt 中定义配色和排版:
private val LightColorScheme = lightColorScheme(
primary = Color(0xFF6200EE),
secondary = Color(0xFF03DAC6)
)
@Composable
fun MyAppTheme(content: @Composable () -> Unit) {
MaterialTheme(
colorScheme = LightColorScheme,
typography = Typography, // 自定义排版
content = content
)
}
使用时包裹需要应用主题的内容:
MyAppTheme {
// 自动使用主题色
Text("主题文本", color = MaterialTheme.colorScheme.primary)
}
列表与延迟加载
对于大量数据,使用 LazyColumn 或 LazyRow 提升性能,它们只组合当前可见的项。
@Composable
fun NameList(names: List<String>) {
LazyColumn {
items(names) { name ->
Text(text = name, modifier = Modifier.padding(8.dp))
}
}
}
导航
Compose 通过 Navigation Compose 库实现页面跳转。
添加依赖:
implementation("androidx.navigation:navigation-compose:2.7.5")
基本使用:
val navController = rememberNavController()
NavHost(navController = navController, startDestination = "home") {
composable("home") { HomeScreen(navController) }
composable("detail/{itemId}") { backStackEntry ->
DetailScreen(itemId = backStackEntry.arguments?.getString("itemId"))
}
}
导航触发:
Button(onClick = { navController.navigate("detail/123") }) {
Text("去详情")
}
实战项目:备忘录应用
结合以上知识,我们快速搭建一个简单的备忘录界面。
1. 数据模型
data class Note(val id: Int, val content: String)
2. 界面组合
@Composable
fun NotesApp() {
var notes by remember { mutableStateOf(listOf<Note>()) }
var newNote by remember { mutableStateOf("") }
Column(modifier = Modifier.padding(16.dp)) {
Row(verticalAlignment = Alignment.CenterVertically) {
TextField(
value = newNote,
onValueChange = { newNote = it },
modifier = Modifier.weight(1f),
label = { Text("新备忘录") }
)
Spacer(modifier = Modifier.width(8.dp))
Button(onClick = {
if (newNote.isNotBlank()) {
notes = notes + Note(id = notes.size, content = newNote)
newNote = ""
}
}) {
Text("添加")
}
}
LazyColumn {
items(notes) { note ->
Card(modifier = Modifier.padding(vertical = 4.dp)) {
Text(note.content, modifier = Modifier.padding(12.dp))
}
}
}
}
}