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

SwiftUI中实现沿圆周路径的缩放、透明度循环动画问题

SwiftUI中实现沿圆周路径的缩放、透明度循环动画问题

嘿,我来帮你搞定这个动画难题!你之前的代码只做了旋转和缩放,但没让图片真正沿着圆周移动——核心问题是没把图片的位置锚定在圆周上,现在我给你梳理清楚思路,再附上修改后的代码:

问题核心分析

要让图片沿着圆周走,得先把图片的中心固定在圆周的边缘,再通过旋转来改变它的位置,同时配合分阶段的缩放、透明度动画。另外要注意SwiftUI的角度坐标系:默认0度在3点钟方向,顺时针为角度增加方向,所以我们先明确几个关键位置的角度:

  • 7点钟方向:120度(从3点顺时针转120度)
  • 11点钟方向:-60度(从3点逆时针转60度)
  • 3点钟方向:0度

实现步骤

  1. 分阶段动画控制:用一个进度值(0到1)把动画分成两段:
    • 0% - 50%:从7点移动到11点,同时缩放从0→1,保持透明度1
    • 50% - 100%:从11点移动到3点,保持缩放1,同时透明度从1→0
  2. 锚定圆周位置:先把图片偏移到圆周的右侧(3点位置),再通过旋转让它沿着圆周移动,这样图片中心始终在圆周上
  3. 循环动画:让进度值循环从0到1,动画结束后瞬间重置,开启下一轮

修改后的完整代码

struct ContentView: View {
    @State private var animationProgress: Double = 0.0
    // 圆周参数:原Circle宽度60,所以半径30;图片大小可自行调整
    private let circleRadius: CGFloat = 30
    private let imageSize: CGFloat = 20
    
    // 计算当前图片的角度(控制圆周位置)
    private var currentAngle: Double {
        if animationProgress < 0.5 {
            // 第一阶段:7点(120°) → 11点(-60°),总变化180°
            let phaseProgress = animationProgress * 2
            return 120 - phaseProgress * 180
        } else {
            // 第二阶段:11点(-60°) → 3点(0°),总变化60°
            let phaseProgress = (animationProgress - 0.5) * 2
            return -60 + phaseProgress * 60
        }
    }
    
    // 计算当前缩放比例
    private var currentScale: CGFloat {
        animationProgress < 0.5 ? CGFloat(animationProgress * 2) : 1.0
    }
    
    // 计算当前透明度
    private var currentOpacity: Double {
        animationProgress < 0.5 ? 1.0 : 1.0 - (animationProgress - 0.5) * 2
    }
    
    var body: some View {
        ZStack {
            Circle()
                .stroke(.black, lineWidth: 1.0)
                .frame(width: circleRadius * 2)
            
            // 动画的图片
            Image(systemName: "circle.fill")
                .resizable()
                .frame(width: imageSize, height: imageSize)
                .foregroundColor(.red)
                .scaleEffect(currentScale)
                .opacity(currentOpacity)
                // 先偏移到圆周右侧(3点位置),让图片中心在圆周上
                .offset(x: circleRadius)
                // 通过旋转改变图片在圆周上的位置
                .rotationEffect(Angle(degrees: currentAngle))
        }
        .onAppear {
            // 启动线性循环动画,时长可自行调整
            withAnimation(Animation.linear(duration: 3).repeatForever(autoreverses: false)) {
                animationProgress = 1.0
            }
        }
    }
}

代码说明

  • 我们用animationProgress来驱动所有动画属性,通过判断进度值来分阶段计算角度、缩放和透明度
  • offset(x: circleRadius)是关键:让图片中心刚好落在圆周边缘,之后的旋转操作就会让它沿着圆周移动
  • 动画用linear保证匀速移动,repeatForever(autoreverses: false)让动画结束后瞬间重置,开启下一轮循环

你可以根据需求调整动画时长、图片大小、圆周尺寸,或者替换成你自己的图片~

备注:内容来源于stack exchange,提问作者batman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 15:38:05