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

Android Compose Crossfade与尺寸变化动画双向同步运行实现问题

问题解决方法

根本原因

Crossfade的默认测量逻辑会在动画过程中保留所有正在执行过渡的内容的尺寸,从展开切换到折叠状态时,正在淡出的展开内容还会被计入测量范围,导致Crossfade的尺寸直到淡出动画完全结束才会缩小,外层animateContentSize因此延迟触发,最终出现两个动画先后执行的问题。

修复代码

使用AnimatedContent替代Crossfade,指定尺寸测量策略为仅匹配目标状态内容,同时配置和淡入淡出匹配的动画规格即可实现双向同步:

var expandedState by remember { mutableStateOf(false) }
// 统一动画时长,保证所有动画步调一致
val animSpec = tween<Float>(durationMillis = 300)

Box(
    modifier = Modifier.animateContentSize(animationSpec = animSpec)
) {
    AnimatedContent(
        targetState = expandedState,
        // 仅按目标状态的内容计算尺寸,动画启动时就会触发尺寸变化
        contentSize = ContentSizeTransform.SizeToTarget(),
        transitionSpec = { fadeIn(animSpec) togetherWith fadeOut(animSpec) },
        label = "expandFadeAnim"
    ) { expanded ->
        if (expanded) {
            ExpandedContent()
        } else {
            CollapsedContent()
        }
    }
}

低版本兼容方案

如果你的Compose版本不支持ContentSizeTransform参数,可以手动控制两个内容的透明度实现同等效果:

var expandedState by remember { mutableStateOf(false) }
val transition = updateTransition(targetState = expandedState, label = "expandTransition")
val animSpec = tween<Float>(durationMillis = 300)

Box(modifier = Modifier.animateContentSize(animationSpec = animSpec)) {
    CollapsedContent(
        modifier = Modifier
            .align(Alignment.TopStart)
            .alpha(transition.animateFloat(label = "collapseAlpha", transitionSpec = { animSpec }) { if (it) 0f else 1f }.value)
    )
    ExpandedContent(
        modifier = Modifier
            .align(Alignment.TopStart)
            .alpha(transition.animateFloat(label = "expandAlpha", transitionSpec = { animSpec }) { if (it) 1f else 0f }.value)
    )
}

内容的提问来源于stack exchange,提问作者Nino van Hooff

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 22:24:01