我正在寻找 AppKit 的 NSHostingView 的等价物用于 UIKit,以便我可以在 UIKit 中嵌入 SwiftUI View 。不幸的是,UIKit 没有与 NSHostingView
等效的类。我们拥有的最接近的相当于 NSHostingController , 命名为 UIHostingController .由于 View Controller 包含 View ,我们应该能够 call the appropriate UIViewController embedding methods , 然后获取 view
并直接使用它。
There are many articles这解释了这是在 UIKit 中嵌入 SwiftUI View 的方式。但是,他们通常无法解释您将如何从 UIKit ➡️ SwiftUI 进行通信。例如,假设我实现了一个充当进度条的 SwiftUI View ,我希望定期更新进度。我希望我的遗留/UIKit 代码更新 SwiftUI View 以显示新进度。
only article I found这接近于解释如何操作嵌入式 View 的内容,建议我们使用 @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)"
}
}
}
这似乎是有道理的,因为计时器应该触发更新 View 的一系列事件:
- ✅
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 View ?
最佳答案
所有你需要的是扔掉那个自定义主题,并使用标准的@Published
,如下所示
class CircleModel: ObservableObject {
@Published var text: String
init(text: String) {
self.text = text
}
}
测试于:Xcode 11.2/iOS 13.2
关于ios - 如何更新嵌入到 UIKit 中的 SwiftUI View ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59219019/