视图控制器不仅仅适用于顶层场景.我们经常在视图控制器中放置视图控制器.它被称为"视图控制器包含"和/或"子视图控制器".(顺便说一句,在传统的UIKit应用程序中,视图控制器容器通常是对抗视图控制器inflating 的好方法,可以将复杂的场景分解为多个视图控制器.)
所以
继续使用UIHostingController
:
let controller = UIHostingController(rootView: ...)
和
添加视图控制器然后可以将主机控制器添加为子视图控制器:
addChild(controller)
view.addSubview(controller.view)
controller.didMove(toParent: self)
显然,您还需要为宿主控制器的view
设置frame
或布局约束.
有关将一个视图控制器嵌入另一个视图控制器的一般信息,请参见UIViewController
documentation的Implementing 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)"
}
}
}