jetpack-compose
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseJetpack Compose Patterns
Jetpack Compose 模式
Modern declarative UI patterns for Android.
适用于Android的现代声明式UI模式。
State Management
状态管理
State Hoisting
状态提升
kotlin
// ✅ CORRECT: Stateless composable
@Composable
fun Counter(
count: Int,
onIncrement: () -> Unit,
modifier: Modifier = Modifier
) {
Row(modifier = modifier) {
Text("Count: $count")
Button(onClick = onIncrement) {
Text("+")
}
}
}
// Parent owns state
@Composable
fun CounterScreen() {
var count by rememberSaveable { mutableStateOf(0) }
Counter(
count = count,
onIncrement = { count++ }
)
}kotlin
// ✅ CORRECT: Stateless composable
@Composable
fun Counter(
count: Int,
onIncrement: () -> Unit,
modifier: Modifier = Modifier
) {
Row(modifier = modifier) {
Text("Count: $count")
Button(onClick = onIncrement) {
Text("+")
}
}
}
// Parent owns state
@Composable
fun CounterScreen() {
var count by rememberSaveable { mutableStateOf(0) }
Counter(
count = count,
onIncrement = { count++ }
)
}Remember Variants
remember的不同变体
kotlin
// remember - Survives recomposition
val alpha by remember { mutableStateOf(1f) }
// rememberSaveable - Survives config change
var count by rememberSaveable { mutableStateOf(0) }
// remember with key - Resets on key change
val animation = remember(itemId) { Animatable(0f) }
// derivedStateOf - Computed, updates only when result changes
val isValid by remember {
derivedStateOf { email.isNotBlank() && password.length >= 8 }
}kotlin
// remember - 可在重组后保留状态
val alpha by remember { mutableStateOf(1f) }
// rememberSaveable - 可在配置变更后保留状态
var count by rememberSaveable { mutableStateOf(0) }
// remember with key - 当key变化时重置状态
val animation = remember(itemId) { Animatable(0f) }
// derivedStateOf - 计算属性,仅当结果变化时更新
val isValid by remember {
derivedStateOf { email.isNotBlank() && password.length >= 8 }
}Composition Patterns
组合模式
Slot API
Slot API
kotlin
@Composable
fun AppBar(
title: @Composable () -> Unit,
navigationIcon: @Composable () -> Unit = {},
actions: @Composable RowScope.() -> Unit = {}
) {
TopAppBar(
title = { title() },
navigationIcon = { navigationIcon() },
actions = actions
)
}
// Usage
AppBar(
title = { Text("Home") },
navigationIcon = { IconButton(onClick = {}) { Icon(Icons.Default.Menu, null) } },
actions = {
IconButton(onClick = {}) { Icon(Icons.Default.Search, null) }
}
)kotlin
@Composable
fun AppBar(
title: @Composable () -> Unit,
navigationIcon: @Composable () -> Unit = {},
actions: @Composable RowScope.() -> Unit = {}
) {
TopAppBar(
title = { title() },
navigationIcon = { navigationIcon() },
actions = actions
)
}
// 使用示例
AppBar(
title = { Text("Home") },
navigationIcon = { IconButton(onClick = {}) { Icon(Icons.Default.Menu, null) } },
actions = {
IconButton(onClick = {}) { Icon(Icons.Default.Search, null) }
}
)Modifier Pattern
Modifier模式
kotlin
@Composable
fun CustomButton(
onClick: () -> Unit,
modifier: Modifier = Modifier, // First optional parameter
enabled: Boolean = true,
content: @Composable RowScope.() -> Unit
) {
Button(
onClick = onClick,
modifier = modifier, // Apply modifier first
enabled = enabled,
content = content
)
}kotlin
@Composable
fun CustomButton(
onClick: () -> Unit,
modifier: Modifier = Modifier, // 第一个可选参数
enabled: Boolean = true,
content: @Composable RowScope.() -> Unit
) {
Button(
onClick = onClick,
modifier = modifier, // 先应用modifier
enabled = enabled,
content = content
)
}Side Effects
副作用处理
LaunchedEffect
LaunchedEffect
kotlin
@Composable
fun HomeScreen(viewModel: HomeViewModel) {
// Runs once
LaunchedEffect(Unit) {
viewModel.loadData()
}
// Runs when key changes
LaunchedEffect(userId) {
viewModel.loadUser(userId)
}
}kotlin
@Composable
fun HomeScreen(viewModel: HomeViewModel) {
// 仅执行一次
LaunchedEffect(Unit) {
viewModel.loadData()
}
// 当key变化时执行
LaunchedEffect(userId) {
viewModel.loadUser(userId)
}
}DisposableEffect
DisposableEffect
kotlin
@Composable
fun LifecycleObserver(onResume: () -> Unit) {
val lifecycleOwner = LocalLifecycleOwner.current
DisposableEffect(lifecycleOwner) {
val observer = LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_RESUME) onResume()
}
lifecycleOwner.lifecycle.addObserver(observer)
onDispose {
lifecycleOwner.lifecycle.removeObserver(observer)
}
}
}kotlin
@Composable
fun LifecycleObserver(onResume: () -> Unit) {
val lifecycleOwner = LocalLifecycleOwner.current
DisposableEffect(lifecycleOwner) {
val observer = LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_RESUME) onResume()
}
lifecycleOwner.lifecycle.addObserver(observer)
onDispose {
lifecycleOwner.lifecycle.removeObserver(observer)
}
}
}Theming
主题配置
Material 3
Material 3
kotlin
@Composable
fun AppTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
val colorScheme = if (darkTheme) DarkColorScheme else LightColorScheme
MaterialTheme(
colorScheme = colorScheme,
typography = AppTypography,
content = content
)
}
// Usage
val backgroundColor = MaterialTheme.colorScheme.surface
val textStyle = MaterialTheme.typography.bodyLargekotlin
@Composable
fun AppTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
val colorScheme = if (darkTheme) DarkColorScheme else LightColorScheme
MaterialTheme(
colorScheme = colorScheme,
typography = AppTypography,
content = content
)
}
// 使用示例
val backgroundColor = MaterialTheme.colorScheme.surface
val textStyle = MaterialTheme.typography.bodyLargeLists
列表组件
LazyColumn
LazyColumn
kotlin
LazyColumn {
items(
items = users,
key = { it.id } // Critical for performance
) { user ->
UserItem(user = user)
}
}kotlin
LazyColumn {
items(
items = users,
key = { it.id } // 对性能至关重要
) { user ->
UserItem(user = user)
}
}Animations
动画实现
Animate Values
数值动画
kotlin
val alpha by animateFloatAsState(
targetValue = if (visible) 1f else 0f,
animationSpec = tween(durationMillis = 300)
)
val size by animateDpAsState(
targetValue = if (expanded) 200.dp else 100.dp
)kotlin
val alpha by animateFloatAsState(
targetValue = if (visible) 1f else 0f,
animationSpec = tween(durationMillis = 300)
)
val size by animateDpAsState(
targetValue = if (expanded) 200.dp else 100.dp
)AnimatedContent
AnimatedContent
kotlin
AnimatedContent(
targetState = state,
transitionSpec = {
fadeIn() togetherWith fadeOut()
}
) { targetState ->
when (targetState) {
is Loading -> LoadingContent()
is Success -> SuccessContent(targetState.data)
is Error -> ErrorContent()
}
}Remember: Compose is declarative. Describe the UI, don't command it.
kotlin
AnimatedContent(
targetState = state,
transitionSpec = {
fadeIn() togetherWith fadeOut()
}
) { targetState ->
when (targetState) {
is Loading -> LoadingContent()
is Success -> SuccessContent(targetState.data)
is Error -> ErrorContent()
}
}注意:Compose是声明式框架。只需描述UI,而非直接操控它。