我正在寻找一个类似于AppKit的NSHostingView的UIKit等效类,以便我可以在UIKit中嵌入SwiftUI视图。不幸的是,UIKit没有与
这似乎是有道理的,因为计时器应该会触发一系列事件来更新视图:
我该如何从UIKit > SwiftUI通信以操作嵌入在UIKit中的SwiftUI视图?
NSHostingView
相对应的等效类。我们最接近的是NSHostingController的等效类UIHostingController。由于视图控制器包含一个视图,因此我们应该能够调用适当的UIViewController嵌入方法,然后获取view
并直接使用它。
有 许多 文章 解释 这是在UIKit中嵌入SwiftUI视图的方法。但是,它们通常无法很好地解释您如何从UIKit ➡️ SwiftUI 进行通信。例如,想象一下我实现了一个作为进度条的SwiftUI视图,我希望定期更新进度。我希望我的传统/UIKit代码可以更新SwiftUI视图以显示新进度。
唯一一篇找到的接近解释如何操作嵌入式视图内容的文章建议我们使用@ObservedObject
:import UIKit
import SwiftUI
import Combine
class CircleModel: ObservableObject {
var didChange = PassthroughSubject<Void, Never>()
var text: String { didSet { didChange.send() } }
init(text: String) {
self.text = text
}
}
struct CircleView : View {
@ObservedObject var model: CircleModel
var body: some View {
ZStack {
Circle()
.fill(Color.blue)
Text(model.text)
.foregroundColor(Color.white)
}
}
}
class ViewController: UIViewController {
private weak var timer: Timer?
private var model = CircleModel(text: "")
override func viewDidLoad() {
super.viewDidLoad()
addCircleView()
startTimer()
}
deinit {
timer?.invalidate()
}
}
private extension ViewController {
func addCircleView() {
let circleView = CircleView(model: model)
let controller = UIHostingController(rootView: circleView)
addChild(controller)
controller.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(controller.view)
controller.didMove(toParent: self)
NSLayoutConstraint.activate([
controller.view.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.5),
controller.view.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.5),
controller.view.centerXAnchor.constraint(equalTo: view.centerXAnchor),
controller.view.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
}
func startTimer() {
var index = 0
timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] _ in
index += 1
self?.model.text = "Tick \(index)"
}
}
}
这似乎是有道理的,因为计时器应该会触发一系列事件来更新视图:
- ✅
self?.model.text = "Tick 1"
(在ViewController.startTimer()
中)。 - ✅
didChange.send()
(在CircleModel.text.didSet
中) - ❌
Text(model.text)
(在CircleView.body
中)
didChange.send()
从未触发对CircleView.body
的重新运行。我该如何从UIKit > SwiftUI通信以操作嵌入在UIKit中的SwiftUI视图?
ObservableObject
已更改为需要一个objectWillChange
发布者而不是一个didChange
发布者。Asperi的答案展示了一种更简单的实现ObservableObject
的方法,即让它从其@Published
属性中合成自己的发布者。 - rob mayoff