本文介绍了在 SwiftUI 中,如何在 UIView 内或作为 UIView 使用 UIHostingController?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

另一个问题标题可以是如何将 UIHostingController 的视图添加为 UIView 的子视图?".

An alternative question title could be "How to add an UIHostingController's view as subview for an UIView?".

我正在创建一个新的 UI 组件,并且很想尝试一下 SwiftUI.下图是当前的视图结构.UIView 是我现在使用的(右上),SwiftUI 视图是我尝试使用的(右下).

I am creating a new piece of UI component and would love to give SwiftUI a try. The image below is the current view structure. The UIView is what I am using right now (top right), and SwiftUI view is what I try to use (bottom right).

在我观看了 WWDC 2019 的所有 SwiftUI 视频后.我仍然不知道如何使用 SwiftUI 视图并将其放在 UIView 实例应该去的地方.

After I watched all SwiftUI videos from WWDC 2019. I still have no clue on how can I use a SwiftUI view and put it at where a UIView instance should go.

我从Integrating SwiftUI"演讲中注意到,macOS 有一个 NSHostingViewhttps://developer.apple.com/documentation/swiftui/nshostingview# 这让我想知道是否有类似的东西或者什么是实现它的替代方法.

I noticed from "Integrating SwiftUI" talk is that there is an NSHostingView for macOS, https://developer.apple.com/documentation/swiftui/nshostingview# which made me wonder if there is something similar to it or what is the alternative to achieve it.

我阅读了诸如在现有 UIKit 应用程序中包含 SwiftUI 视图之类的问题提到 SwiftUI 和 UIKit 可以与 UIHostingController 一起玩.然而,我想要做的是只采用一小块 SwiftUI 并将其放入我现有的 UIKit 视图组件中,而不是将其用作控制器.

I read questions like Include SwiftUI views in existing UIKit application mentioned that SwiftUI and UIKit can play together with UIHostingController. However, what I am trying to do is to only adopt one small piece of SwiftUI and put it inside of my existing UIKit view component, not use it as a controller.

我是 iOS 开发的新手,如果有一种方法可以将视图控制器用作 UIView 视图,请发表评论.谢谢.

I am new to iOS development, please leave a comment if there is a way I can use view controller as UIView view. Thank you.

推荐答案

视图控制器不仅仅用于顶级场景.我们经常将视图控制器放在视图控制器中.它被称为视图控制器包含"和/或子视图控制器".(顺便说一句,一般来说,视图控制器容器是解决传统 UIKit 应用中视图控制器膨胀的好方法,将复杂的场景分解为多个视图控制器.)

View controllers are not just for the top level scene. We often place view controllers within view controllers. It’s called "view controller containment" and/or "child view controllers". (BTW, view controller containers are, in general, a great way to fight view controller bloat in traditional UIKit apps, breaking complicated scenes into multiple view controllers.)

所以,

  • 继续使用UIHostingController:

let controller = UIHostingController(rootView: ...)

和;

添加视图控制器然后可以将宿主控制器添加为子视图控制器:

Add the view controller can then add the hosting controller as a child view controller:

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

显然,您还需要为宿主控制器的 view 设置 frame 或布局约束.

Obviously, you’d also set the frame or the layout constraints for the hosting controller’s view.

请参阅UIViewController 实现容器视图控制器部分="noreferrer">文档,了解有关将一个视图控制器嵌入另一个视图控制器的一般信息.

See the Implementing a Container View Controller section of the UIViewController documentation for general information about embedding one view controller within another.

例如,假设我们有一个 SwiftUI 视图来渲染一个带有文本的圆:

For example, let’s imagine that we had a SwiftUI View to render a circle with text in it:

struct CircleView : View {
    @ObservedObject var model: CircleModel

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

假设这是我们视图的模型:

And let’s say this was our view’s model:

import Combine

class CircleModel: ObservableObject {
    @Published var text: String

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

然后我们的 UIKit 视图控制器可以添加 SwiftUI 视图,在 UIView 中设置其框架/约束,并根据需要更新其模型:

Then our UIKit view controller could add the SwiftUI view, set its frame/constraints within the UIView, and update its model as you see fit:

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

这篇关于在 SwiftUI 中,如何在 UIView 内或作为 UIView 使用 UIHostingController?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-29 14:33