ios - 如何更新嵌入到 UIKit 中的 SwiftUI View ?

标签 ios swift uikit swiftui

我正在寻找 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 的一系列事件:

  1. self?.model.text = "Tick 1"(在 ViewController.startTimer() 中)。
  2. didChange.send()(在 CircleModel.text.didSet 中)
  3. 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/

相关文章:

android - 如何检测系统的中文、韩文和英文字体而不分别嵌入一种字体? (Android 和 IOS 上的 AIR 移动版)

javascript - 获取 JSON 数据时遇到问题

iphone - 在 xCode 中加载自定义 UIFonts

ios - 无法导入桥接头 '/MyProject-Bridging.h'

compiler-errors - 限制表达式中的术语数?

ios - 了解 UIDynamics 如何计算位置

uikit - SwiftUI 通过实现 UIViewRepresentable 使用 UIKit 组件

iPhone SDK - 大 UITableViewCell

ios - 应用程序缺少默认组排行榜(ItunesConnect 错误)

ios - 核心图 : Autoscaling y-axis labels according to plot data