当容器视图控制器动态更改子视图控制器时布局不起作用
Layout not working when container view controller dynamically changes child view controller
我有一个 MainViewController,其中包含一个 ContainerViewController。
ContainerViewController 开始显示 childViewControllerA,并在单击 childViewControllerA 中的按钮时动态切换到 childViewControllerB :
func showNextViewContoller() {
let childViewControllerB = ChildViewControllerB()
container.addViewController(childViewControllerB)
container.children.first?.remove() // Remove childViewControllerA
}
这是一张图表:
第二个视图控制器 (ViewControllerB) 有一个我想在中心显示的图像视图。所以我给它分配了以下约束:
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFill
NSLayoutConstraint.activate([
imageView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
imageView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
imageView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.6),
])
我 运行 遇到的问题是 imageView 没有垂直居中:它低于应有的位置。
当我 运行 应用程序以便 ContainerVeiwController 首先显示 childViewControllerB 时,它会按预期工作。只有在 childViewControllerA:
之后动态切换 childViewControllerB 时才会出现此问题
为了帮助调试,我在所有三个 ViewController 中添加了以下代码:
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
print("MainViewController bounds = \(self.view.bounds)")
}
这给出了一个有趣的打印输出(运行在 iPhone 13 迷你模拟器上打印):
MainViewController bounds = (0.0, 0.0, 375.0, 812.0) //iPhone 13 mini screen is 375 x 812
ChildViewControllerA bounds = (0.0, 0.0, 375.0,738.0). // 812 - 50 safety margin - 24 titlebar = 738.
现在,在单击按钮并添加子 ViewControllerB 后发生切换:
ChildViewControllerB bounds = (0.0, 0.0, 375.0, 812.0)
似乎 ChildViewControllerB 假设全屏大小并忽略其父视图控制器 (ContainerViewController) 的边界。所以,imageView的hightAnchor是基于全屏高度的,导致它出现偏心。
因此,我将 imageView 的约束更改为:
NSLayoutConstraint.activate([
imageView.centerYAnchor.constraint(equalTo: super.view.centerYAnchor),
imageView.centerXAnchor.constraint(equalTo: super.view.centerXAnchor),
imageView.heightAnchor.constraint(equalTo: super.view.heightAnchor, multiplier: 0.6),
])
接下来,我试图通过在上面的 showNextViewController() 函数中发生切换后添加这些行来强制更新布局:
container.children.first?.view.layoutSubviews()
//and
container.children.first?.view.setNeedsLayout()
None 他们工作了。
如何让 ChildViewControllerB 遵守 ContainerViewController 的边界?
如果有帮助,imageView 最初只需要位于中心即可。它最终会附带一个平移、捏合和旋转手势,因此用户可以将它移动到他们想要的任何地方。
编辑 01:
这就是我添加和删除子视图控制器的方式:
extension UIViewController {
func addViewController(_ child: UIViewController) {
addChild(child)
view.addSubview(child.view)
child.didMove(toParent: self)
}
func remove() {
guard parent != nil else { return }
willMove(toParent: nil)
view.removeFromSuperview()
removeFromParent()
}
}
编辑 02:
根据一些评论员的推荐,我更新了 addViewController() 函数:
func addViewController(_ child: UIViewController) {
addChild(child)
view.addSubview(child.view)
child.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
child.view.topAnchor.constraint(equalTo: self.view.topAnchor),
child.view.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
child.view.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
child.view.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
])
child.didMove(toParent: self)
}
这似乎不起作用,我收到错误消息“无法同时满足约束条件。”不幸的是,我对如何破译错误信息知之甚少...
编辑 03:简化项目:
这是一个简化的项目。有四个文件加上 AppDelegate(我没有使用故事板):
- 主要ViewController
- ViewController一个
- ViewControllerB
- 实用工具
- AppDelegate
主要ViewController:
import UIKit
class MainViewController: UIViewController {
let titleBarView = UIView(frame: .zero)
let container = UIViewController()
override func viewDidLoad() {
super.viewDidLoad()
setup()
layout()
}
func setup() {
titleBarView.backgroundColor = .gray
view.addSubview(titleBarView)
addViewController(container)
showViewControllerA()
}
func layout() {
titleBarView.translatesAutoresizingMaskIntoConstraints = false
container.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
titleBarView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
titleBarView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
titleBarView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
titleBarView.heightAnchor.constraint(equalToConstant: 24),
container.view.topAnchor.constraint(equalTo: titleBarView.bottomAnchor, constant: 0),
container.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
container.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
container.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
])
}
func showViewControllerA() {
let viewControllerA = ViewControllerA()
viewControllerA.delegate = self
container.children.first?.remove()
container.addViewController(viewControllerA)
}
func showViewControllerB() {
let viewControllerB = ViewControllerB()
container.children.first?.remove()
container.addViewController(viewControllerB)
}
}
extension MainViewController: ViewControllerADelegate {
func nextViewController() {
showViewControllerB()
}
}
ViewController答:
protocol ViewControllerADelegate: AnyObject {
func nextViewController()
}
class ViewControllerA: UIViewController {
let nextButton = UIButton()
weak var delegate: ViewControllerADelegate?
override func viewDidLoad() {
super.viewDidLoad()
setup()
layout()
view.backgroundColor = .gray
}
func setup() {
nextButton.setTitle("next", for: .normal)
nextButton.addTarget(self, action: #selector(nextButtonPressed), for: .primaryActionTriggered)
view.addSubview(nextButton)
}
func layout() {
nextButton.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
nextButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
nextButton.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
}
@objc func nextButtonPressed() {
delegate?.nextViewController()
}
}
ViewController乙:
导入 UIKit
class ViewControllerB: UIViewController {
let imageView = UIImageView()
override func viewDidLoad() {
super.viewDidLoad()
setup()
layout()
}
func setup() {
view.addSubview(imageView)
blankImage()
}
func layout() {
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFill
imageView.layer.magnificationFilter = CALayerContentsFilter.nearest;
NSLayoutConstraint.activate([
imageView.centerYAnchor.constraint(equalTo: super.view.centerYAnchor),
imageView.centerXAnchor.constraint(equalTo: super.view.centerXAnchor),
imageView.heightAnchor.constraint(equalTo: super.view.heightAnchor, multiplier: 0.6),
])
view.layoutSubviews()
}
func blankImage() {
let ciImage = CIImage(cgImage: createBlankCGImage(width: 32, height: 64)!)
imageView.image = cIImageToUIImage(ciimage: ciImage, context: CIContext())
}
}
实用程序:
import Foundation
import UIKit
func createBlankCGImage(width: Int, height: Int) -> CGImage? {
let bounds = CGRect(x: 0, y:0, width: width, height: height)
let intWidth = Int(ceil(bounds.width))
let intHeight = Int(ceil(bounds.height))
let bitmapContext = CGContext(data: nil,
width: intWidth, height: intHeight,
bitsPerComponent: 8,
bytesPerRow: 0,
space: CGColorSpace(name: CGColorSpace.sRGB)!,
bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)
if let cgContext = bitmapContext {
cgContext.saveGState()
let r = CGFloat.random(in: 0...1)
let g = CGFloat.random(in: 0...1)
let b = CGFloat.random(in: 0...1)
cgContext.setFillColor(red: r, green: g, blue: b, alpha: 1)
cgContext.fill(bounds)
cgContext.restoreGState()
return cgContext.makeImage()
}
return nil
}
func cIImageToUIImage(ciimage: CIImage, context: CIContext) -> UIImage? {
if let cgimg = context.createCGImage(ciimage, from: ciimage.extent) {
return UIImage(cgImage: cgimg)
}
return nil
}
extension UIViewController {
func addViewController(_ child: UIViewController) {
addChild(child)
view.addSubview(child.view)
child.didMove(toParent: self)
}
func remove() {
guard parent != nil else { return }
willMove(toParent: nil)
view.removeFromSuperview()
removeFromParent()
}
}
AppDelegate:
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.backgroundColor = .white
window?.makeKeyAndVisible()
window?.rootViewController = MainViewController()
return true
}
}
更新如下:
func addViewController(_ child: UIViewController) {
addChild(child)
view.addSubview(child.view)
child.didMove(toParent: self)
child.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
child.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
child.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
child.view.topAnchor.constraint(equalTo: view.topAnchor),
child.view.bottomAnchor.constraint(equalTo: view.bottomAnchor)])
}
在MainViewViewController中更新layout()函数:
func layout() {
titleBarView.translatesAutoresizingMaskIntoConstraints = false
container.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
titleBarView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
titleBarView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
titleBarView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
titleBarView.heightAnchor.constraint(equalToConstant: 24),
//container.view.topAnchor.constraint(equalTo: titleBarView.bottomAnchor, constant: 0),
//container.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
//container.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
//container.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
])
}
小行星走在正确的轨道上,但还有一些其他问题...
您没有给子控制器的视图任何约束,因此它们以“原始”大小加载。
按照 Asteroid 的建议更改 addViewController(...)
函数可以解决 A
和 B
缺少的约束,但是...
您正在为您的 container
控制器调用相同的函数 并且 在 [=18= 中为其视图添加约束],所以你最终会遇到约束冲突。
一个解决方案是将您的 addViewController
函数更改为:
func addViewController(_ child: UIViewController, constrainToSuperview: Bool = true) {
addChild(child)
view.addSubview(child.view)
if constrainToSuperview {
child.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
child.view.topAnchor.constraint(equalTo: view.topAnchor),
child.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
child.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
child.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
])
}
child.didMove(toParent: self)
}
然后在 setup()
:
func setup() {
titleBarView.backgroundColor = .red
view.addSubview(titleBarView)
// change this
//addViewController(container)
// to this
addViewController(container, constrainToSuperview: false)
showViewControllerA()
}
同时留下您的其他“添加视图控制器”调用,如下所示:
container.addViewController(viewControllerA)
container.addViewController(viewControllerB)
另一件可能让您失望的事情是图像视图约束中的无关 super.
:
NSLayoutConstraint.activate([
// change this
//imageView.centerYAnchor.constraint(equalTo: super.view.centerYAnchor),
//imageView.centerXAnchor.constraint(equalTo: super.view.centerXAnchor),
//imageView.heightAnchor.constraint(equalTo: super.view.heightAnchor, multiplier: 0.6),
// to this
imageView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
imageView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
imageView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.6),
])
我有一个 MainViewController,其中包含一个 ContainerViewController。
ContainerViewController 开始显示 childViewControllerA,并在单击 childViewControllerA 中的按钮时动态切换到 childViewControllerB :
func showNextViewContoller() {
let childViewControllerB = ChildViewControllerB()
container.addViewController(childViewControllerB)
container.children.first?.remove() // Remove childViewControllerA
}
这是一张图表:
第二个视图控制器 (ViewControllerB) 有一个我想在中心显示的图像视图。所以我给它分配了以下约束:
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFill
NSLayoutConstraint.activate([
imageView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
imageView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
imageView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.6),
])
我 运行 遇到的问题是 imageView 没有垂直居中:它低于应有的位置。
当我 运行 应用程序以便 ContainerVeiwController 首先显示 childViewControllerB 时,它会按预期工作。只有在 childViewControllerA:
之后动态切换 childViewControllerB 时才会出现此问题为了帮助调试,我在所有三个 ViewController 中添加了以下代码:
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
print("MainViewController bounds = \(self.view.bounds)")
}
这给出了一个有趣的打印输出(运行在 iPhone 13 迷你模拟器上打印):
MainViewController bounds = (0.0, 0.0, 375.0, 812.0) //iPhone 13 mini screen is 375 x 812
ChildViewControllerA bounds = (0.0, 0.0, 375.0,738.0). // 812 - 50 safety margin - 24 titlebar = 738.
现在,在单击按钮并添加子 ViewControllerB 后发生切换:
ChildViewControllerB bounds = (0.0, 0.0, 375.0, 812.0)
似乎 ChildViewControllerB 假设全屏大小并忽略其父视图控制器 (ContainerViewController) 的边界。所以,imageView的hightAnchor是基于全屏高度的,导致它出现偏心。
因此,我将 imageView 的约束更改为:
NSLayoutConstraint.activate([
imageView.centerYAnchor.constraint(equalTo: super.view.centerYAnchor),
imageView.centerXAnchor.constraint(equalTo: super.view.centerXAnchor),
imageView.heightAnchor.constraint(equalTo: super.view.heightAnchor, multiplier: 0.6),
])
接下来,我试图通过在上面的 showNextViewController() 函数中发生切换后添加这些行来强制更新布局:
container.children.first?.view.layoutSubviews()
//and
container.children.first?.view.setNeedsLayout()
None 他们工作了。
如何让 ChildViewControllerB 遵守 ContainerViewController 的边界?
如果有帮助,imageView 最初只需要位于中心即可。它最终会附带一个平移、捏合和旋转手势,因此用户可以将它移动到他们想要的任何地方。
编辑 01:
这就是我添加和删除子视图控制器的方式:
extension UIViewController {
func addViewController(_ child: UIViewController) {
addChild(child)
view.addSubview(child.view)
child.didMove(toParent: self)
}
func remove() {
guard parent != nil else { return }
willMove(toParent: nil)
view.removeFromSuperview()
removeFromParent()
}
}
编辑 02:
根据一些评论员的推荐,我更新了 addViewController() 函数:
func addViewController(_ child: UIViewController) {
addChild(child)
view.addSubview(child.view)
child.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
child.view.topAnchor.constraint(equalTo: self.view.topAnchor),
child.view.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
child.view.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
child.view.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
])
child.didMove(toParent: self)
}
这似乎不起作用,我收到错误消息“无法同时满足约束条件。”不幸的是,我对如何破译错误信息知之甚少...
编辑 03:简化项目:
这是一个简化的项目。有四个文件加上 AppDelegate(我没有使用故事板):
- 主要ViewController
- ViewController一个
- ViewControllerB
- 实用工具
- AppDelegate
主要ViewController:
import UIKit
class MainViewController: UIViewController {
let titleBarView = UIView(frame: .zero)
let container = UIViewController()
override func viewDidLoad() {
super.viewDidLoad()
setup()
layout()
}
func setup() {
titleBarView.backgroundColor = .gray
view.addSubview(titleBarView)
addViewController(container)
showViewControllerA()
}
func layout() {
titleBarView.translatesAutoresizingMaskIntoConstraints = false
container.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
titleBarView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
titleBarView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
titleBarView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
titleBarView.heightAnchor.constraint(equalToConstant: 24),
container.view.topAnchor.constraint(equalTo: titleBarView.bottomAnchor, constant: 0),
container.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
container.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
container.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
])
}
func showViewControllerA() {
let viewControllerA = ViewControllerA()
viewControllerA.delegate = self
container.children.first?.remove()
container.addViewController(viewControllerA)
}
func showViewControllerB() {
let viewControllerB = ViewControllerB()
container.children.first?.remove()
container.addViewController(viewControllerB)
}
}
extension MainViewController: ViewControllerADelegate {
func nextViewController() {
showViewControllerB()
}
}
ViewController答:
protocol ViewControllerADelegate: AnyObject {
func nextViewController()
}
class ViewControllerA: UIViewController {
let nextButton = UIButton()
weak var delegate: ViewControllerADelegate?
override func viewDidLoad() {
super.viewDidLoad()
setup()
layout()
view.backgroundColor = .gray
}
func setup() {
nextButton.setTitle("next", for: .normal)
nextButton.addTarget(self, action: #selector(nextButtonPressed), for: .primaryActionTriggered)
view.addSubview(nextButton)
}
func layout() {
nextButton.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
nextButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
nextButton.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
}
@objc func nextButtonPressed() {
delegate?.nextViewController()
}
}
ViewController乙:
导入 UIKit
class ViewControllerB: UIViewController {
let imageView = UIImageView()
override func viewDidLoad() {
super.viewDidLoad()
setup()
layout()
}
func setup() {
view.addSubview(imageView)
blankImage()
}
func layout() {
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFill
imageView.layer.magnificationFilter = CALayerContentsFilter.nearest;
NSLayoutConstraint.activate([
imageView.centerYAnchor.constraint(equalTo: super.view.centerYAnchor),
imageView.centerXAnchor.constraint(equalTo: super.view.centerXAnchor),
imageView.heightAnchor.constraint(equalTo: super.view.heightAnchor, multiplier: 0.6),
])
view.layoutSubviews()
}
func blankImage() {
let ciImage = CIImage(cgImage: createBlankCGImage(width: 32, height: 64)!)
imageView.image = cIImageToUIImage(ciimage: ciImage, context: CIContext())
}
}
实用程序:
import Foundation
import UIKit
func createBlankCGImage(width: Int, height: Int) -> CGImage? {
let bounds = CGRect(x: 0, y:0, width: width, height: height)
let intWidth = Int(ceil(bounds.width))
let intHeight = Int(ceil(bounds.height))
let bitmapContext = CGContext(data: nil,
width: intWidth, height: intHeight,
bitsPerComponent: 8,
bytesPerRow: 0,
space: CGColorSpace(name: CGColorSpace.sRGB)!,
bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)
if let cgContext = bitmapContext {
cgContext.saveGState()
let r = CGFloat.random(in: 0...1)
let g = CGFloat.random(in: 0...1)
let b = CGFloat.random(in: 0...1)
cgContext.setFillColor(red: r, green: g, blue: b, alpha: 1)
cgContext.fill(bounds)
cgContext.restoreGState()
return cgContext.makeImage()
}
return nil
}
func cIImageToUIImage(ciimage: CIImage, context: CIContext) -> UIImage? {
if let cgimg = context.createCGImage(ciimage, from: ciimage.extent) {
return UIImage(cgImage: cgimg)
}
return nil
}
extension UIViewController {
func addViewController(_ child: UIViewController) {
addChild(child)
view.addSubview(child.view)
child.didMove(toParent: self)
}
func remove() {
guard parent != nil else { return }
willMove(toParent: nil)
view.removeFromSuperview()
removeFromParent()
}
}
AppDelegate:
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.backgroundColor = .white
window?.makeKeyAndVisible()
window?.rootViewController = MainViewController()
return true
}
}
更新如下:
func addViewController(_ child: UIViewController) {
addChild(child)
view.addSubview(child.view)
child.didMove(toParent: self)
child.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
child.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
child.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
child.view.topAnchor.constraint(equalTo: view.topAnchor),
child.view.bottomAnchor.constraint(equalTo: view.bottomAnchor)])
}
在MainViewViewController中更新layout()函数:
func layout() {
titleBarView.translatesAutoresizingMaskIntoConstraints = false
container.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
titleBarView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
titleBarView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
titleBarView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
titleBarView.heightAnchor.constraint(equalToConstant: 24),
//container.view.topAnchor.constraint(equalTo: titleBarView.bottomAnchor, constant: 0),
//container.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
//container.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
//container.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
])
}
小行星走在正确的轨道上,但还有一些其他问题...
您没有给子控制器的视图任何约束,因此它们以“原始”大小加载。
按照 Asteroid 的建议更改 addViewController(...)
函数可以解决 A
和 B
缺少的约束,但是...
您正在为您的 container
控制器调用相同的函数 并且 在 [=18= 中为其视图添加约束],所以你最终会遇到约束冲突。
一个解决方案是将您的 addViewController
函数更改为:
func addViewController(_ child: UIViewController, constrainToSuperview: Bool = true) {
addChild(child)
view.addSubview(child.view)
if constrainToSuperview {
child.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
child.view.topAnchor.constraint(equalTo: view.topAnchor),
child.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
child.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
child.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
])
}
child.didMove(toParent: self)
}
然后在 setup()
:
func setup() {
titleBarView.backgroundColor = .red
view.addSubview(titleBarView)
// change this
//addViewController(container)
// to this
addViewController(container, constrainToSuperview: false)
showViewControllerA()
}
同时留下您的其他“添加视图控制器”调用,如下所示:
container.addViewController(viewControllerA)
container.addViewController(viewControllerB)
另一件可能让您失望的事情是图像视图约束中的无关 super.
:
NSLayoutConstraint.activate([
// change this
//imageView.centerYAnchor.constraint(equalTo: super.view.centerYAnchor),
//imageView.centerXAnchor.constraint(equalTo: super.view.centerXAnchor),
//imageView.heightAnchor.constraint(equalTo: super.view.heightAnchor, multiplier: 0.6),
// to this
imageView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
imageView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
imageView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.6),
])