簡體   English   中英

在 SwiftUI 中,如何在 UIView 內或作為 UIView 使用 UIHostingController?

[英]In SwiftUI, how to use UIHostingController inside an UIView or as an UIView?

另一個問題標題可能是“如何將 UIHostingController 的視圖添加為 UIView 的子視圖?” .

我正在創建一個新的 UI 組件,並且很想嘗試一下 SwiftUI。 下圖是當前的視圖結構。 UIView 是我現在正在使用的(右上),而 SwiftUI 視圖是我嘗試使用的(右下)。

在此處輸入圖像描述

在我觀看了 WWDC 2019 的所有 SwiftUI 視頻之后。我仍然不知道如何使用 SwiftUI 視圖並將其放在 UIView 實例應該去的位置。

我從“Integrating SwiftUI”談話中注意到有一個適用於 macOS 的NSHostingViewhttps://developer.apple.com/documentation/swiftui/nshostingview#這讓我想知道是否有類似的東西或者有什么替代品實現這一目標。

我閱讀了諸如Include SwiftUI views in existing UIKit application 之類的問題,提到 SwiftUI 和 UIKit 可以與UIHostingController一起玩。 然而,我想做的是只采用一小部分 SwiftUI 並將其放在我現有的 UIKit 視圖組件中,而不是將其用作控制器。

我是 iOS 開發的新手,如果有辦法可以將視圖控制器用作 UIView 視圖,請發表評論。 謝謝你。

視圖控制器不僅適用於頂級場景。 我們經常將視圖控制器放在視圖控制器中。 它被稱為“視圖控制器包含”和/或“子視圖控制器”。 (順便說一句,視圖控制器容器通常是對抗傳統 UIKit 應用程序中視圖控制器膨脹的好方法,將復雜的場景分解為多個視圖控制器。)

所以,

  • 繼續使用UIHostingController

     let controller = UIHostingController(rootView: ...)

    和;

  • 添加視圖控制器然后可以將宿主控制器添加為子視圖控制器:

     addChild(controller) view.addSubview(controller.view) controller.didMove(toParent: self)

    顯然,您還需要為宿主控制器的view設置frame或布局約束。

    有關將一個視圖控制器嵌入另一個視圖控制器的一般信息,請參閱UIViewController 文檔實現容器視圖控制器部分。


例如,假設我們有一個 SwiftUI 視圖來渲染一個帶有文本的圓圈:

struct CircleView : View {
    @ObservedObject var model: CircleModel

    var body: some View {
        ZStack {
            Circle()
                .fill(Color.blue)
            Text(model.text)
                .foregroundColor(Color.white)
        }
    }
}

假設這是我們視圖的模型:

import Combine

class CircleModel: ObservableObject {
    @Published var text: String

    init(text: String) {
        self.text = text
    }
}

然后我們的 UIKit 視圖控制器可以添加 SwiftUI 視圖,在UIView中設置它的框架/約束,並根據你認為合適的方式更新它的模型:

import UIKit
import SwiftUI

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)"
        }
    }
}

我有一些想法。

  1. 用 UIHostingController 包裝UIHostingController
  2. 初始化控制器
  3. 將新控制器添加為子視圖控制器
  4. 將控制器視圖作為子視圖添加到它應該去的地方

因此:

addChild(hostingViewController)
hostingViewController.view.frame = ...
view.addSubview(hostingViewController.view)
hostingViewController.didMove(toParent: self)

視圖控制器總是使用其他視圖控制器作為視圖。

斯坦福 CS193P, https: //youtu.be/w7a79cx3UaY?t=679

參考

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM