iOS 17更新后EaseInOut动画无法正常工作问题求助
iOS 17下SwiftUI循环淡入淡出动画停止问题
我写了一个Blink ViewModifier,在iOS 16里能持续平滑地淡入淡出,但升级到iOS 17后,动画只跑几次就停了。
相关代码:
struct Blink: ViewModifier { @State private var opacity = 0.0 var isActive: Bool func body(content: Content) -> some View { if isActive { content .opacity(self.opacity) .animation(.easeInOut(duration: 0.5) .repeatCount(1) .repeatForever(autoreverses: true), value: self.opacity) .onAppear { DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { self.opacity = 1 } }.onChange(of: opacity) { print(opacity) } } else { content } } }
iOS 17下的动画效果:
问题根源
iOS 17对SwiftUI动画的重复逻辑做了调整,原代码里同时用.repeatCount(1)和.repeatForever(autoreverses: true)会造成动画系统冲突。再加上只靠一次opacity值变更触发动画,iOS 17的动画优化机制会判定动画已完成,直接终止循环。
修复方案
方案1:清理重复配置,简化动画触发
删掉多余的.repeatCount(1),让永久重复的动画逻辑正常生效:
struct Blink: ViewModifier { @State private var opacity = 0.0 var isActive: Bool func body(content: Content) -> some View { Group { if isActive { content .opacity(opacity) .animation( .easeInOut(duration: 0.5) .repeatForever(autoreverses: true), value: opacity ) .onAppear { // 保留原有的延迟触发,按需调整或直接移除延迟 DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { opacity = 1 } } } else { content } } } }
方案2:用Timer主动控制动画状态(更稳定)
如果方案1还是有问题,用Timer周期性切换opacity值,确保动画持续触发:
struct Blink: ViewModifier { @State private var opacity = 0.0 @State private var timer: Timer? var isActive: Bool let animationDuration: Double = 0.5 func body(content: Content) -> some View { Group { if isActive { content .opacity(opacity) .animation(.easeInOut(duration: animationDuration), value: opacity) .onAppear { startBlinkTimer() } .onDisappear { timer?.invalidate() } .onChange(of: isActive) { newValue in if newValue { startBlinkTimer() } else { timer?.invalidate() opacity = 0 // 重置透明度 } } } else { content } } } private func startBlinkTimer() { timer?.invalidate() // 动画往返一次的时间是duration*2 timer = Timer.scheduledTimer(withTimeInterval: animationDuration * 2, repeats: true) { _ in opacity = opacity == 0 ? 1 : 0 } // 初始延迟触发一次,和原逻辑保持一致 DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { opacity = 1 } } }
方案3:用AnimatableModifier自定义动画(精准控制)
如果需要更底层的动画控制,实现AnimatableModifier:
struct Blink: AnimatableModifier { var isActive: Bool private var progress: Double = 0 var animatableData: Double { get { progress } set { progress = newValue } } func body(content: Content) -> some View { content .opacity(isActive ? sin(progress * .pi) : 1) .onAppear { guard isActive else { return } withAnimation(.easeInOut(duration: 0.5).repeatForever(autoreverses: false)) { progress = .infinity } } .onChange(of: isActive) { newValue in guard newValue else { progress = 0 return } withAnimation(.easeInOut(duration: 0.5).repeatForever(autoreverses: false)) { progress = .infinity } } } }
内容的提问来源于stack exchange,提问作者Mohamed Said
相关产品推荐
相关产品推荐

