基于Apple Watch常亮场景阶段切换的动画未按预期运行
问题根因
你的代码存在两个核心问题导致动画无法恢复:
- 按scenePhase切换两套完全重复的ZStack结构,场景从非活跃切回活跃态时,活跃分支的ZStack不会再次触发onAppear(仅视图首次加载时会调用onAppear),animate状态不会更新,动画自然不会重启。
- 使用了无指定绑定值的animation修饰符,隐式动画触发时机不可控,也会导致动画恢复异常。
修正方案
直接通过状态控制动画启停,无需重复创建视图,同时监听scenePhase变化主动触发动画重启,修正后代码如下:
struct PulseView: View { @Environment(\.scenePhase) private var scenePhase @State var animate = false // 补充你原有逻辑中缺失的自定义属性/方法,可根据实际需求调整 private func circlesColor() -> Color { .red } private let outerCircleSize: CGFloat = 100 private let middleCircleSize: CGFloat = 60 private let innerCircleSize: CGFloat = 20 var body: some View { ZStack { ZStack { Circle().fill(circlesColor().opacity(0.25)).frame(width: outerCircleSize, height: outerCircleSize).scaleEffect(self.animate ? 1 : 0.01) Circle().fill(circlesColor().opacity(0.35)).frame(width: middleCircleSize, height: middleCircleSize).scaleEffect(self.animate ? 1 : 0.01) Circle().fill(circlesColor()).frame(width: innerCircleSize, height: innerCircleSize) } // 明确动画绑定的变化值,避免隐式动画异常 .animation(animate ? Animation.easeInOut(duration: 1.5).repeatForever(autoreverses: true) : .default, value: animate) // 监听场景状态变化,主动控制动画启停 .onChange(of: scenePhase) { newPhase in if newPhase == .active { // 先重置再启动,避免状态更新被合并导致动画不触发 animate = false DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) { animate = true } } else { animate = false } } .onAppear { animate = true } } } }
调整说明
- 删掉重复的视图分支,无需根据scenePhase切换整个视图结构,避免视图重复创建带来的生命周期异常
- 新增
onChange监听scenePhase变化:场景回到活跃状态时,先重置animate为false再重新赋值为true,强制动画从头触发;非活跃状态下直接停止动画,符合常亮模式的适配要求 - 给
animation修饰符增加value: animate参数,明确动画仅响应animate值的变化,避免无效隐式动画干扰
内容的提问来源于stack exchange,提问作者GarySabo
相关产品推荐
相关产品推荐

