在 SwiftUI 中,如何在 UIView 内或作为 UIView 使用 UIHostingController? [英] In SwiftUI, how to use UIHostingController inside an UIView or as an UIView?
问题描述
另一个问题标题可以是如何将 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 有一个 NSHostingView
,https://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?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!