问题描述
另一个问题标题可能是如何将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.
我从集成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
文档,了解有关将一个视图控制器嵌入另一个视图控制器的一般信息.
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?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!