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

SwiftUI中如何让加载动画切换refreshing时完成当前周期

解决SwiftUI加载动画切换时无法完成当前周期的问题

当前实现的问题在于,直接通过refreshing绑定值切换视图分支,会导致动画被强制中断,无法完成当前旋转周期。要实现动画优雅完成当前周期后再停止,需要调整状态管理和动画控制逻辑:

修改后的完整实现

import SwiftUI

public struct RefreshingView : View {
    @State private var rotation = Angle(degrees: 0.0)
    @Binding private var refreshing: Bool
    // 新增状态变量,控制动画实际播放状态
    @State private var isAnimating = false
    
    public init(refreshing: Binding<Bool>) {
        _refreshing = refreshing
    }

    public var body: some View {
        Image(systemName: "arrow.2.circlepath")
            .foregroundColor(.red)
            .rotationEffect(rotation)
            .onChange(of: refreshing) { newValue in
                if newValue {
                    // 开始动画
                    isAnimating = true
                    startRotationAnimation()
                } else {
                    // 标记停止,等待当前周期结束后复位
                    isAnimating = false
                }
            }
            .onAppear {
                if refreshing {
                    isAnimating = true
                    startRotationAnimation()
                }
            }
    }
    
    private func startRotationAnimation() {
        guard isAnimating else { return }
        
        // 执行单次180度旋转动画,时长1秒
        withAnimation(.linear(duration: 1)) {
            rotation = rotation + Angle(degrees: -180)
        } completion: {
            // 动画完成后判断是否继续循环
            if isAnimating {
                startRotationAnimation()
            } else {
                // 停止后复位到初始角度
                withAnimation(.linear(duration: 0.3)) {
                    rotation = .zero
                }
            }
        }
    }
}

关键改进说明

  • 分离状态控制:用isAnimating状态变量单独控制动画循环,避免直接依赖refreshing绑定值导致视图切换中断动画
  • 手动循环动画:放弃repeatForever,改用单次动画+完成回调的方式手动控制循环,这样可以在refreshing变为false时,让当前动画完成后再停止
  • 平滑复位:动画停止后,通过一个短动画将旋转角度复位到初始状态,避免突兀跳转
  • 统一视图结构:移除原有的if-else视图分支,始终显示同一个Image,消除视图切换带来的视觉断层

低版本兼容方案

如果需要兼容iOS 15以下版本(withAnimation的completion回调仅iOS15+支持),可以改用延迟回调判断周期结束:

private func startRotationAnimation() {
    guard isAnimating else { return }
    
    withAnimation(.linear(duration: 1)) {
        rotation = rotation + Angle(degrees: -180)
    }
    
    DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
        if isAnimating {
            startRotationAnimation()
        } else {
            withAnimation(.linear(duration: 0.3)) {
                rotation = .zero
            }
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 04:41:02