You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose:updateTransition完成监听与动画顺序实现问询

Jetpack Compose 动画问题解决方案

先看你提供的基础代码:

val transition = updateTransition(animValue, label = "iconstate")

val offsetVal by transition.animateFloat(
    label = "rocket1 offset"
) { animated ->
   Log.d("Wuh", "AnimatedIconMovement hjhjdahda: $animated")
    if (animated) 1f else 0f
}
val sizeAnimate by transition.animateDp(label="size dp", targetValueByState = {
    if(it) 60.dp else 20.dp
})

问题1:监听updateTransition的动画完成状态

有两种实用方式:

方式1:添加状态变化监听器

直接给transition绑定addStatusChangeListener,当动画状态变为Completed时触发回调:

transition.addStatusChangeListener { status ->
    if (status == TransitionStatus.Completed) {
        // 这里写动画完成后的逻辑,比如打印日志、触发后续操作
        Log.d("Animation", "整个Transition动画执行完毕")
    }
}

方式2:用LaunchedEffect监听状态同步

通过对比transition的currentState和targetState,当两者相等时说明动画完成:

LaunchedEffect(transition.targetState) {
    snapshotFlow { transition.currentState == transition.targetState }
        .filter { it }
        .collect {
            Log.d("Animation", "Transition动画已完成")
            // 执行动画完成后的操作
        }
}

问题2:实现offsetVal动画先执行,完成后再启动sizeAnimate动画

核心是分阶段控制动画触发时机,以下两种方案都可行:

方案1:用多状态枚举拆分动画阶段

定义密封类标记动画的不同阶段,让updateTransition基于状态逐步切换:

// 定义动画阶段状态
sealed class AnimationPhase {
    object Idle : AnimationPhase()
    object RunningOffset : AnimationPhase()
    object RunningSize : AnimationPhase()
}

// 持有当前动画阶段的状态
var currentPhase by remember { mutableStateOf(AnimationPhase.Idle) }

// 触发顺序动画的入口(比如绑定到点击事件)
fun startSequentialAnimation() {
    currentPhase = AnimationPhase.RunningOffset
}

// 负责offset动画的Transition
val offsetTransition = updateTransition(currentPhase, label = "offset-transition")
val offsetVal by offsetTransition.animateFloat(label = "rocket1 offset") { phase ->
    when (phase) {
        AnimationPhase.RunningOffset -> 1f
        else -> 0f
    }
}

// 监听offset动画完成,切换到size动画阶段
LaunchedEffect(offsetTransition.targetState) {
    snapshotFlow { offsetTransition.currentState == offsetTransition.targetState }
        .filter { it && offsetTransition.targetState == AnimationPhase.RunningOffset }
        .collect {
            currentPhase = AnimationPhase.RunningSize
        }
}

// 负责size动画的Transition
val sizeTransition = updateTransition(currentPhase, label = "size-transition")
val sizeAnimate by sizeTransition.animateDp(label = "size dp") { phase ->
    when (phase) {
        AnimationPhase.RunningSize -> 60.dp
        else -> 20.dp
    }
}

方案2:利用单个动画的finishedListener触发后续动画

拆分两个独立状态变量,在offset动画完成后触发size动画的状态切换:

// 分别控制offset和size动画的状态变量
var animateOffset by remember { mutableStateOf(false) }
var animateSize by remember { mutableStateOf(false) }

// 触发顺序动画的入口
fun startSequentialAnimation() {
    animateOffset = true
}

// offset动画,完成后启动size动画
val offsetVal by updateTransition(animateOffset, label = "offset-transition").animateFloat(
    label = "rocket1 offset",
    finishedListener = {
        // offset动画执行完毕,触发size动画
        animateSize = true
    }
) { animated ->
    if (animated) 1f else 0f
}

// size动画
val sizeAnimate by updateTransition(animateSize, label = "size-transition").animateDp(
    label = "size dp"
) { animated ->
    if (animated) 60.dp else 20.dp
}

内容的提问来源于stack exchange,提问作者Gaurav Roy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 23:35:35