SwiftUI图片缩放透明度循环动画:切换至录制状态重复触发
解决SwiftUI录制按钮动画重复触发问题
核心问题是.onAppear仅在视图首次渲染时执行,当从其他状态切回recording时,对应的ZStack视图可能并未被销毁重建,所以动画不会重新触发。我们可以通过监听状态变化来替代.onAppear,确保每次进入recording状态都能启动动画。
修改方案
- 监听
recordState的变化,当状态切换为.recording时启动循环动画 - 切换到其他状态时,重置动画参数并停止循环
修改后的完整代码
enum RecordState { case recording case notRecording case none } // 假设这是你的View结构体内部代码 @State private var recordState: RecordState = .none @State private var scale: CGFloat = 0.8 // 动画初始缩放值 @State private var opacity: Double = 1.0 // 动画初始透明度 VStack { Button { switch recordState { case .recording: recordState = .notRecording case .notRecording: recordState = .none case .none: recordState = .recording } } label: { switch recordState { case .recording: ZStack { Image("ic_record_cancel") .resizable() .frame(width: 76, height: 76) .zIndex(1.0) Image("ic_record_effect") .resizable() .frame(width: 76, height: 76) .zIndex(0.1) .opacity(opacity) .scaleEffect(scale) // 监听recordState变化,替代onAppear .onChange(of: recordState) { newState in if newState == .recording { // 创建循环动画 let baseAnimation = Animation.linear(duration: 0.8).delay(0.2) let repeatedAnimation = baseAnimation.repeatForever(autoreverses: true) withAnimation(repeatedAnimation) { scale = 1.0 opacity = 0.6 } } else { // 切换到其他状态时重置动画参数,停止动画 withAnimation(.linear) { scale = 0.8 opacity = 1.0 } } } } case .notRecording, .none: Image("ic_record_start") .resizable() .frame(width: 76, height: 76) } } }
关键说明
- 把动画触发逻辑从
.onAppear移到.onChange(of: recordState)中,每次状态变为.recording都会执行动画启动代码 - 切换到非录制状态时,重置
scale和opacity到初始值,自动停止循环动画 - 初始的
scale和opacity设为动画的起始状态,保证动画过渡自然
内容的提问来源于stack exchange,提问作者imjohnnotsina
相关产品推荐
相关产品推荐

