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

Jetpack Compose动画圆形实现求助:无法复现GIF所示效果

修复Jetpack Compose动画圆形效果的问题

问题分析

你的代码存在几个关键问题导致无法达到预期效果:

  • 变形因子突变:randomFloatInRange在动画目标值中会每次重复时生成新随机数,导致圆形变形幅度突然变化,无法平滑过渡。
  • 路径起始点不匹配:手动设置的moveTo坐标和循环绘制的点公式不一致,导致路径闭合时出现不自然的缺口或折线。
  • 动画控制逻辑问题:rememberInfiniteTransition的无限循环特性无法在isAnimating为false时优雅停止动画,且两个动画的节奏和同步性不符合示例效果。
  • 波形数量不符:sin(rad * 5)生成的凸起数量和示例GIF中的数量不匹配。

修正后的代码

@Composable
fun AnimatedCircleDemo(isAnimating: Boolean) {
    // 使用Animatable更灵活控制动画启停
    val scaleAnim = remember { Animatable(1.9f) }
    val deformAnim = remember { Animatable(0f) }

    LaunchedEffect(isAnimating) {
        if (isAnimating) {
            // 同时启动两个同步的无限重复动画
            launch {
                scaleAnim.animateTo(
                    targetValue = 2.05f,
                    animationSpec = infiniteRepeatable(
                        animation = tween(1000, easing = FastOutSlowInEasing),
                        repeatMode = RepeatMode.Reverse
                    )
                )
            }
            launch {
                deformAnim.animateTo(
                    targetValue = 0.15f, // 固定变形幅度,保证平滑过渡
                    animationSpec = infiniteRepeatable(
                        animation = tween(1000, easing = LinearOutSlowInEasing),
                        repeatMode = RepeatMode.Reverse
                    )
                )
            }
        } else {
            // 停止动画并重置到初始状态
            scaleAnim.animateTo(1.9f, animationSpec = tween(300))
            deformAnim.animateTo(0f, animationSpec = tween(300))
        }
    }

    Canvas(modifier = Modifier.fillMaxSize()) {
        val center = Offset(size.width / 2, size.height / 2)
        val radius = 100f * scaleAnim.value
        val deformFactor = deformAnim.value
        val waveCount = 4 // 匹配示例中的凸起数量

        val path = Path()
        // 从角度0的点开始绘制,保证路径连贯
        val startRad = Math.toRadians(0.0)
        val startX = center.x + radius * (1 + deformFactor * Math.sin(startRad * waveCount)) * Math.cos(startRad)
        val startY = center.y + radius * (1 + deformFactor * Math.sin(startRad * waveCount)) * Math.sin(startRad)
        path.moveTo(startX.toFloat(), startY.toFloat())

        // 循环绘制所有角度点,步长5度提升平滑度
        for (angle in 5..360 step 5) {
            val rad = Math.toRadians(angle.toDouble())
            val x = center.x + radius * (1 + deformFactor * Math.sin(rad * waveCount)) * Math.cos(rad)
            val y = center.y + radius * (1 + deformFactor * Math.sin(rad * waveCount)) * Math.sin(rad)
            path.lineTo(x.toFloat(), y.toFloat())
        }

        path.close()
        drawPath(path, Color.Blue) // 替换为你的颜色逻辑
    }
}

关键修改点说明

  1. 替换动画控制方式:用Animatable替代rememberInfiniteTransition,可以更灵活地根据isAnimating状态启停动画,并在停止时平滑重置。
  2. 固定变形幅度:将随机目标值改为固定的0.15f,确保变形效果平滑往复,不会出现突变。
  3. 统一路径起始点:使用和循环绘制一致的公式计算起始点,避免路径断裂。
  4. 调整波形数量:将waveCount设为4,匹配示例GIF中的凸起数量,让视觉效果更接近预期。
  5. 优化角度步长:将步长从10度改为5度,提升圆形边缘的平滑度。

内容的提问来源于stack exchange,提问作者Hahw Jdjd

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 00:26:17