另一个问题的标题可以是"How to add an UIHostingController's view as subview for an UIView?".

我正在创建一个新的UI组件,很想try 一下SwiftUI.下图是当前视图 struct .UIView是我现在使用的(右上角),SwiftUI视图是我try 使用的(右下角).

enter image description here

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

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

我读过像Include SwiftUI views in existing UIKit application这样的问题,其中提到SwiftUI和UIKit可以与UIHostingController一起玩.然而,我试图做的是只采用一小块SwiftUI,并将其放在我现有的UIKit视图组件中,而不是将其用作控制器.

我是iOS开发新手,如果有办法将view controller用作UIView,请留言.非常感谢.

推荐答案

视图控制器不仅仅适用于顶层场景.我们经常在视图控制器中放置视图控制器.它被称为"视图控制器包含"和/或"子视图控制器".(顺便说一句,在传统的UIKit应用程序中,视图控制器容器通常是对抗视图控制器inflating 的好方法,可以将复杂的场景分解为多个视图控制器.)

所以

  • 继续使用UIHostingController:

    let controller = UIHostingController(rootView: ...)
    

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

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

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

    有关将一个视图控制器嵌入另一个视图控制器的一般信息,请参见UIViewController documentationImplementing a Container View Controller部分.


例如,假设我们有一个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)"
        }
    }
}

Swift相关问答推荐

Swift-Can无法在AudioKit中找出简单的麦克风效果-文件链

一种函数,用于判断变量的类型是否为在SWIFT中作为参数传递的类型

String.Index encodedOffset已弃用,但建议的替代方案不起作用

SwiftUI 中的同一个 ForEach 中是否可以有 2 个数组?

VisionOS TabBar预览中是否存在漏洞?

为什么Swift可以在没有足够信息的情况下推断类型?

SwiftUI .task 视图修改器:运行在哪个线程中?

如何使用 Swift 在非本地函数中切换()一个 Bool?

SwiftUI:列表背景为空列表时为黑色

ScreenCaptureKit/CVPixelBuffer 格式产生意外结果

使用 RxSwift 围绕 async/await 方法创建 Observable

使用列表的下一项更新相同的视图

将内容与工作表顶部而不是中间对齐

异步等待不会在项目中触发,但在 Xcode playground 中工作正常

为什么swiftui中的导航视图栏那么大?

What is "SwiftPM.SPMRepositoryError error 5"?

iOS Swift - 如何更改表格视图的背景 colored颜色 ?

快速的 AES 加密

滑动侧边栏菜单 IOS 8 Swift

对分段控制的快速处理动作