如何在MainViewController的ContainerView中展示ConceptGalleryViewController?
你的问题根源在于两个核心错误:一是直接用performSegue会默认替换整个视图控制器栈,导致侧边菜单消失、画廊全屏显示;二是后来尝试实例化新的MainViewController时,这个新实例的视图还没完成加载,systemContainerView自然是nil,触发了崩溃。
正确的思路是让ConceptViewController通知已存在的MainViewController,由MainViewController负责把ConceptGalleryViewController加载到容器视图里,而不是自己跳转或者创建新的MainVC实例。下面是具体的实现步骤:
第一步:给ConceptViewController添加回调闭包
我们用闭包实现父子控制器间的通信,让ConceptVC能通知MainVC加载画廊:
// ConceptViewController.swift var onGalleryButtonTapped: ((Int) -> Void)? // 定义闭包,用于传递画廊ID @IBAction func shareTheFunBtnChecked(_ sender: Any) { idGallery = 1 // 触发闭包,把画廊ID传给MainVC onGalleryButtonTapped?(idGallery) }
第二步:修改MainViewController的容器加载逻辑
先优化showSubViewInContainerView方法,移除容器里已有的子视图和子控制器(避免多个视图重叠),然后在加载ConceptVC的时候绑定闭包:
// MainViewController.swift func showSubViewInContainerView(view: String){ // 先清理容器里已有的子控制器和视图 for childVC in self.children { childVC.willMove(toParent: nil) childVC.view.removeFromSuperview() childVC.removeFromParent() } let targetVC = storyboard!.instantiateViewController(withIdentifier: view) addChild(targetVC) targetVC.view.translatesAutoresizingMaskIntoConstraints = false systemContainerView.addSubview(targetVC.view) // 绑定约束,让子视图填满容器 NSLayoutConstraint.activate([ targetVC.view.leadingAnchor.constraint(equalTo: systemContainerView.leadingAnchor), targetVC.view.trailingAnchor.constraint(equalTo: systemContainerView.trailingAnchor), targetVC.view.topAnchor.constraint(equalTo: systemContainerView.topAnchor), targetVC.view.bottomAnchor.constraint(equalTo: systemContainerView.bottomAnchor) ]) // 如果加载的是ConceptVC,绑定闭包 if let conceptVC = targetVC as? ConceptViewController { conceptVC.onGalleryButtonTapped = { [weak self] galleryId in // 收到通知后,加载画廊到容器 self?.showGalleryInContainer(galleryId: galleryId) } } targetVC.didMove(toParent: self) }
第三步:新增加载画廊的专用方法(用于传递ID)
如果需要把idGallery传递给ConceptGalleryViewController,我们可以写一个专用方法:
// MainViewController.swift func showGalleryInContainer(galleryId: Int) { // 同样先清理旧的子视图 for childVC in self.children { childVC.willMove(toParent: nil) childVC.view.removeFromSuperview() childVC.removeFromParent() } let galleryVC = storyboard!.instantiateViewController(withIdentifier: "ConceptGalleryView") as! ConceptGalleryViewController galleryVC.idGallery = galleryId // 传递画廊ID addChild(galleryVC) galleryVC.view.translatesAutoresizingMaskIntoConstraints = false systemContainerView.addSubview(galleryVC.view) // 绑定约束 NSLayoutConstraint.activate([ galleryVC.view.leadingAnchor.constraint(equalTo: systemContainerView.leadingAnchor), galleryVC.view.trailingAnchor.constraint(equalTo: systemContainerView.trailingAnchor), galleryVC.view.topAnchor.constraint(equalTo: systemContainerView.topAnchor), galleryVC.view.bottomAnchor.constraint(equalTo: systemContainerView.bottomAnchor) ]) galleryVC.didMove(toParent: self) }
为什么之前的代码会崩溃?
你之前实例化了新的MainViewController:
let viewController = self.storyboard?.instantiateViewController(withIdentifier: "MainView") as! MainViewController
这个新实例的view还没有被系统加载(未调用viewDidLoad),所以systemContainerView这个IBOutlet还未初始化,自然是nil,调用viewController.systemContainerView.addSubview就会触发崩溃。我们要复用的是当前已经显示在屏幕上的MainVC实例,而不是新建一个。
这样修改后,点击ConceptVC里的按钮,就会通知MainVC把GalleryVC加载到容器视图里,侧边菜单也会保留,完全符合你的布局需求。
内容的提问来源于stack exchange,提问作者triff

