跳转到正文
YGJoon
返回

Android Kotlin Compose 动画进阶

编辑文章

动画 API 总览

API用途
animate*AsState基于状态的简单动画
updateTransition管理多个动画属性
AnimatedVisibility显隐动画
rememberInfiniteTransition循环动画
Animatable手势驱动、物理动画
AnimationSpec自定义动画曲线

复杂场景示例

1. 多属性过渡

enum class CardState { Collapsed, Expanded }

@Composable
fun ExpandableCard(state: CardState) {
    val transition = updateTransition(state, label = "cardTransition")
    val height by transition.animateDp(label = "height") {
        if (it == CardState.Expanded) 240.dp else 72.dp
    }
    val alpha by transition.animateFloat(label = "alpha") {
        if (it == CardState.Expanded) 1f else 0f
    }

    Card(modifier = Modifier.height(height)) {
        Text("Details", modifier = Modifier.alpha(alpha))
    }
}

2. Gesture + Animatable

@Composable
fun SwipeToDismiss(onDismissed: () -> Unit) {
    val offsetX = remember { Animatable(0f) }
    val scope = rememberCoroutineScope()

    Box(modifier = Modifier
        .pointerInput(Unit) {
            detectHorizontalDragGestures(
                onDragEnd = {
                    scope.launch {
                        if (offsetX.value > size.width * 0.4f) {
                            offsetX.animateTo(size.width.toFloat(), tween(200))
                            onDismissed()
                        } else {
                            offsetX.animateTo(0f, spring())
                        }
                    }
                }
            ) { _, dragAmount ->
                scope.launch { offsetX.snapTo((offsetX.value + dragAmount).coerceAtLeast(0f)) }
            }
        }
        .offset { IntOffset(offsetX.value.roundToInt(), 0) }
    ) {
        // content
    }
}

3. 无限动画

@Composable
fun LoadingDots() {
    val infiniteTransition = rememberInfiniteTransition(label = "loading")
    val alpha by infiniteTransition.animateFloat(
        initialValue = 0.3f,
        targetValue = 1f,
        animationSpec = infiniteRepeatable(
            animation = tween(600, easing = FastOutLinearInEasing),
            repeatMode = RepeatMode.Reverse
        ),
        label = "alpha"
    )
    Box(modifier = Modifier.size(12.dp).background(Color.White.copy(alpha = alpha), CircleShape))
}

AnimationSpec

示例:

val spec = keyframes {
    durationMillis = 1200
    0f at 0 with LinearOutSlowInEasing
    1.2f at 400
    0.95f at 800
    1f at 1200
}

性能优化

动画与导航

composable(
    route = "detail",
    enterTransition = { fadeIn(tween(200)) + slideIntoContainer(AnimatedContentTransitionScope.SlideDirection.Left) },
    exitTransition = { fadeOut(tween(200)) }
) { DetailScreen() }

调试技巧

常见问题

问题原因解决方案
动画闪烁状态更新频繁或 key 不稳定保证 remember 使用正确,设置稳定 key
手势滞后Animatable 更新频繁使用 snapTo 控制更新频率
帧率不稳动画逻辑在主线程阻塞将重运算转移到 Dispatchers.Default

总结

Compose 动画体系灵活强大。掌握 Transition、Animatable、InfiniteTransition 等核心 API,可实现复杂交互动效。结合性能调优与调试工具,可以确保动画在不同设备上保持顺滑体验。


编辑文章
分享这篇文章:

上一篇
Android Kotlin Compose 可访问性与无障碍
下一篇
Android Kotlin Compose Material 3 设计体系