SwiftUI中如何判断PhaseAnimator动画何时完成
SwiftUI中判断PhaseAnimator完成周期动画并实现通知的方法
核心逻辑
PhaseAnimator的动画周期由预定义的阶段序列驱动,判断整个周期完成的核心是跟踪阶段(Phase)的状态变化:当动画从最后一个阶段切换回初始阶段(完成一轮循环),或者单次动画执行到最后一个阶段时,即可判定周期完成,此时触发通知即可。
实现步骤与代码示例
1. 定义动画阶段枚举
先明确所有动画阶段,方便管理序列顺序:
enum AnimationPhase: CaseIterable { case start, middle, end // 可根据动画需求自定义阶段数量与类型 }
2. 跟踪阶段变化并触发完成通知
通过@State变量记录当前和历史阶段,在阶段切换时检测周期完成条件:
struct CycleAnimationView: View { @State private var currentPhase: AnimationPhase = .start @State private var previousPhase: AnimationPhase = .start // 自定义通知名称,避免系统通知冲突 private let cycleCompletedNotification = NSNotification.Name("AnimationCycleFinished") var body: some View { // 示例动画视图:随阶段缩放变色的圆形 Circle() .frame(width: 100, height: 100) .phaseAnimator(AnimationPhase.allCases, trigger: currentPhase) { content, phase in content .foregroundColor(phase == .start ? .blue : phase == .middle ? .green : .red) .scaleEffect(phase == .start ? 1 : phase == .middle ? 1.5 : 1) } animation: { phase in // 为每个阶段配置独立动画参数 switch phase { case .start: .easeIn(duration: 0.5) case .middle: .easeOut(duration: 0.5) case .end: .easeInOut(duration: 0.5) } } .onChange(of: currentPhase) { oldPhase, newPhase in previousPhase = oldPhase // 循环动画完成判定:从最后一个阶段切回初始阶段 if newPhase == .start && oldPhase == .end { sendCompletionNotification() } // 单次动画完成判定:当前阶段为最后一个阶段 // if newPhase == .end { // sendCompletionNotification() // } } // 可选:添加手动触发动画的按钮 .overlay( Button("启动循环") { withAnimation { // 手动切换阶段,模拟循环逻辑 currentPhase = currentPhase == .end ? .start : AnimationPhase.allCases[AnimationPhase.allCases.firstIndex(of: currentPhase)! + 1] } } .padding() .background(.black) .foregroundColor(.white) .cornerRadius(8) , alignment: .bottom ) } private func sendCompletionNotification() { // 发送全局通知 NotificationCenter.default.post(name: cycleCompletedNotification, object: nil) print("动画周期已完成") } }
3. 监听动画完成通知
在需要响应动画完成的视图中,通过onReceive监听通知并执行后续逻辑:
struct ContentView: View { private let cycleCompletedNotification = NSNotification.Name("AnimationCycleFinished") @State private var animationStatus: String = "等待动画启动" var body: some View { VStack(spacing: 30) { CycleAnimationView() Text("当前状态:\(animationStatus)") .font(.headline) } .onReceive(NotificationCenter.default.publisher(for: cycleCompletedNotification)) { _ in animationStatus = "动画周期完成!" // 这里可以添加弹窗、数据更新等业务逻辑 } } }
额外说明
- 如果使用PhaseAnimator的自动循环(通过
repeatBehavior配置),上述阶段变化的判断逻辑依然有效,每次循环结束都会触发通知。 - 若不需要全局通知,也可以直接在
sendCompletionNotification方法中直接调用业务逻辑闭包,替代NotificationCenter。
内容的提问来源于stack exchange,提问作者Dubon Ya'ar
相关产品推荐
相关产品推荐

