SwiftUI macOS符号动画切换问题:需点击即时中断旧动画启动新动画
解决SwiftUI齿轮动画快速点击中断问题
你的问题根源在于依赖symbolEffect的预设旋转动画,这类动画默认会排队执行,无法被新的操作即时中断。要实现点击按钮时立即中断旧动画、从当前状态切换旋转方向的效果,可以手动控制旋转角度,结合显式动画实现:
struct TestView: View { // 记录当前旋转的角度值 @State private var rotationAngle: Double = 0 // 标记旋转方向,1为顺时针,-1为逆时针 @State private var direction: Double = 1 var body: some View { Button(action: { // 切换旋转方向 direction *= -1 // 计算新的目标角度,基于当前角度累加360度(按方向) let targetAngle = rotationAngle + 360 * direction // 启动动画,直接从当前角度过渡到目标角度,自动中断旧动画 withAnimation(.easeInOut(duration: 2)) { rotationAngle = targetAngle } }, label: { Label("", systemImage: "gearshape.circle.fill") .font(.system(size: 50)) .foregroundStyle(Color.black) // 绑定旋转角度到视图 .rotationEffect(.degrees(rotationAngle)) }) } }
核心逻辑说明
- 抛弃
symbolEffect的预设动画,改用rotationEffect直接绑定旋转角度,完全掌控动画状态 - 每次点击按钮时,直接切换方向并计算新的目标角度,
withAnimation会立即中断当前动画,从当前角度平滑过渡到新目标 - 这种方式下,无论点击速度多快,动画都会即时响应,不会出现排队等待的情况
可选优化:无限循环旋转
如果需要齿轮持续旋转(而非单次转360度),可以调整为无限循环的动画逻辑:
struct TestView: View { @State private var isClockwise: Bool = true @State private var rotationAngle: Double = 0 var body: some View { Button(action: { isClockwise.toggle() // 保留当前角度的余数,确保从当前状态开始新方向旋转 rotationAngle = rotationAngle.truncatingRemainder(dividingBy: 360) }, label: { Label("", systemImage: "gearshape.circle.fill") .font(.system(size: 50)) .foregroundStyle(Color.black) .rotationEffect(.degrees(rotationAngle)) .animation( .easeInOut(duration: 2) .repeatForever(autoreverses: false), value: isClockwise ) .onChange(of: isClockwise) { newValue in // 根据方向设置旋转增量,触发持续旋转 rotationAngle += newValue ? 360 : -360 } }) } }
内容的提问来源于stack exchange,提问作者Kaven
相关产品推荐
相关产品推荐

