You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

嵌入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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 12:34:54