如果存在内部动画,UIHostingController 中的 SwiftUI 视图在帧动画期间渲染不正确

sol*_*ell 5 uikit ios swift swiftui

当为 a 的帧变化设置动画时,如果当前有正在进行的内部动画,则UIHostingController渲染的内部将不会设置大小变化的动画。View

这是一个已知问题还是我应该做一些不同的事情?我必须想象这是一个非常常见的用例。我已经在 iOS 13.3 和 14.2 上对此进行了测试。

以下是该问题的屏幕截图:https://www.loom.com/share/91eb220dad244c848161330b574e22df

请注意,您在帧动画期间会看到黄色的 UIView 背景,尽管您永远不应该看到它。渲染的 SwiftUI 视图立即更改为最终帧大小,并且仅对原点进行动画处理。

import UIKit
import SwiftUI


// When `true`, issue presents itself.
let animate = true


struct SwiftUIView: View {

    @State var appeared = false

    let animation = Animation
        .default
        .repeatForever(autoreverses: false)

    var body: some View {
        ZStack {
            Color.pink
            Image(systemName: "rays")
                .resizable()
                .frame(width: 50, height: 50)
                .rotationEffect(appeared ? .degrees(360) : .zero)
                .onAppear {
                    withAnimation(animation) {
                        if animate {
                            appeared = true
                        }
                    }
                }
        }
    }
}


class ViewController: UIViewController {

    var vc: UIViewController!

    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = .blue
        view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(didTap)))

        vc = UIHostingController(rootView: SwiftUIView())
        vc.view.backgroundColor = .yellow

        self.addChild(vc)
        view.addSubview(vc.view)
        vc.view.frame = CGRect(x: 50, y: 50, width: 400, height: 100)
        vc.didMove(toParent: self)
    }

    @objc private func didTap() {
        UIView.animate(withDuration: 4) {
            self.vc.view.frame = CGRect(x: 300, y: 300, width: 100, height: 400)
            self.view.layoutIfNeeded()
        }
    }
}

Run Code Online (Sandbox Code Playgroud)