嵌入Sheet的带动画层UIViewRepresentable无法执行动画?
问题原因
Sheet 中动画失效的核心原因是:在 makeUIView 中添加动画时,UIImageView 尚未完全加入到窗口的视图层级中,导致 Core Animation 无法正确启动动画。
修复方案(基于现有遗留代码)
自定义 UIImageView 子类,在视图真正加入窗口时(didMoveToWindow 生命周期方法)添加动画,确保动画在合适的时机启动:
import SwiftUI @main struct MyApp: App { var body: some Scene { WindowGroup { ContentView() } } } // 自定义UIImageView子类,在视图加入窗口时添加动画 class AnimatedMicrophoneView: UIImageView { override func didMoveToWindow() { super.didMoveToWindow() // 避免重复添加动画 guard layer.animation(forKey: "scale") == nil else { return } let animation = CABasicAnimation(keyPath: "transform.scale") animation.duration = 1.3 animation.repeatCount = .greatestFiniteMagnitude animation.autoreverses = true animation.fromValue = 0.9 animation.toValue = 1.1 // 配置动画属性,确保动画持续生效 animation.fillMode = .forwards animation.isRemovedOnCompletion = false layer.add(animation, forKey: "scale") } } struct Microphone: UIViewRepresentable { func updateUIView(_ uiView: AnimatedMicrophoneView, context: Context) { } func makeUIView(context: Context) -> AnimatedMicrophoneView { let view = AnimatedMicrophoneView( image: UIImage( systemName: "mic.circle.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 50,weight: .bold, scale: .large) )? .withRenderingMode(.alwaysTemplate) ) view.translatesAutoresizingMaskIntoConstraints = false view.tintColor = .green return view } } struct ContentView: View { @State var showSheet = false var body: some View { VStack { Microphone() .frame(width: 50, height: 50) Button("Show Sheet") { showSheet = true } .padding(.top) } .sheet(isPresented: $showSheet) { VStack { Microphone() .frame(width: 50, height: 50) } } } } #Preview { ContentView() }
纯SwiftUI平滑动画方案
无需依赖UIKit,用SwiftUI原生API即可实现完全一致的平滑缩放动画:
import SwiftUI @main struct MyApp: App { var body: some Scene { WindowGroup { ContentView() } } } struct SwiftUIMicrophone: View { @State private var scale: CGFloat = 0.9 var body: some View { Image(systemName: "mic.circle.fill") .resizable() .scaledToFit() .foregroundColor(.green) .frame(width: 50, height: 50) .scaleEffect(scale) .onAppear { withAnimation(Animation.easeInOut(duration: 1.3) .repeatForever(autoreverses: true)) { scale = 1.1 } } } } struct ContentView: View { @State var showSheet = false var body: some View { VStack { SwiftUIMicrophone() Button("Show Sheet") { showSheet = true } .padding(.top) } .sheet(isPresented: $showSheet) { VStack { SwiftUIMicrophone() } } } } #Preview { ContentView() }
该方案优势:
- 完全原生SwiftUI实现,无需跨UIKit桥接
- 动画行为与原Core Animation版本完全一致,平滑度相同
- 自动适配SwiftUI视图生命周期,在sheet中可正常启动
内容的提问来源于stack exchange,提问作者Rudedog
相关产品推荐
相关产品推荐

