Swift 4:如何让ViewController加载不同UIView以减少控制器数量
问题:如何让单个UIViewController加载不同自定义UIView?
我平时开发多视图应用习惯一个ViewController对应一个视图,但现在做大型应用不想创建15+个ViewController,想让单个ViewController加载不同的UIView。比如菜单栏选“Settings”时,让selectionController加载Settings View。目前已经能导航到对应控制器且导航栏显示正确,但不知道怎么让控制器加载指定UIView。
相关代码如下:
选中选项时的调用函数
//Whatever option selected will affect which view is inherited let option = self.menuOptions[indexPath.row] if option.name != "Home" { self.homeController?.displayController(menuOption: menuOption, view: self.settingsView) }
Home Controller代码
class HomeController: UIViewController { lazy var menu: Menu = { let menuLauncher = Menu() menuLauncher.homeController = self return menuLauncher }() override func viewDidLoad() { super.viewDidLoad() navigationItem.title = "Home" view.backgroundColor = Color.blue navigationItem.leftBarButtonItem = UIBarButtonItem(image: UIImage(named: "menu"), style: .plain, target: self, action: #selector(displayMenu)) } func displayController(menuOption: MenuOption, view: UIView) { let selectionController = UIViewController() selectionController.navigationItem.title = menuOption.name selectionController.view.backgroundColor = Color.blue //Why dosen't this present the view I have assigned to it?? selectionController.view.addSubview(HomeView(frame: view.frame)) navigationController?.navigationBar.tintColor = UIColor.white navigationController?.pushViewController(selectionController, animated: true) } @objc func displayMenu() { menu.displayMenu() } }
现在这段代码没法正常加载指定UIView,求解决办法?
解决方案
你的问题主要出在几个细节上,我来一步步帮你修正:
1. 修复View的初始化与约束问题
你现在直接用HomeView(frame: view.frame)初始化,而且没有设置自动布局约束,这会导致自定义View的位置、大小不符合预期,甚至完全看不到。正确的做法是让自定义View自动填满控制器的view:
func displayController(menuOption: MenuOption, view: UIView) { let selectionController = UIViewController() selectionController.navigationItem.title = menuOption.name selectionController.view.backgroundColor = .blue // 直接使用传入的自定义View实例,不要重新创建HomeView! let customView = view customView.translatesAutoresizingMaskIntoConstraints = false selectionController.view.addSubview(customView) // 添加约束让自定义View填满控制器的view NSLayoutConstraint.activate([ customView.topAnchor.constraint(equalTo: selectionController.view.topAnchor), customView.leadingAnchor.constraint(equalTo: selectionController.view.leadingAnchor), customView.trailingAnchor.constraint(equalTo: selectionController.view.trailingAnchor), customView.bottomAnchor.constraint(equalTo: selectionController.view.bottomAnchor) ]) navigationController?.navigationBar.tintColor = .white navigationController?.pushViewController(selectionController, animated: true) }
2. 避免无效的View实例创建
你原来的代码里,明明已经传入了self.settingsView,却又重新创建了HomeView,这就导致你传进来的SettingsView根本没被用到,完全是画蛇添足,直接使用传入的view参数即可。
3. 优化方案:封装通用的ContentViewController
如果要多次复用这种“加载不同自定义View”的逻辑,最好封装一个专门的控制器类,让代码更整洁易维护:
class ContentViewController: UIViewController { private let contentView: UIView init(contentView: UIView, title: String) { self.contentView = contentView super.init(nibName: nil, bundle: nil) self.navigationItem.title = title } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .blue contentView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(contentView) NSLayoutConstraint.activate([ contentView.topAnchor.constraint(equalTo: view.topAnchor), contentView.leadingAnchor.constraint(equalTo: view.leadingAnchor), contentView.trailingAnchor.constraint(equalTo: view.trailingAnchor), contentView.bottomAnchor.constraint(equalTo: view.bottomAnchor) ]) } }
之后在displayController里可以这样调用:
func displayController(menuOption: MenuOption, view: UIView) { let contentVC = ContentViewController(contentView: view, title: menuOption.name) navigationController?.navigationBar.tintColor = .white navigationController?.pushViewController(contentVC, animated: true) }
4. 检查自定义View的初始化逻辑
确保你的SettingsView(或其他自定义View)初始化正确,比如如果是用XIB创建的,要正确加载:
class SettingsView: UIView { override init(frame: CGRect) { super.init(frame: frame) commonInit() } required init?(coder: NSCoder) { super.init(coder: coder) commonInit() } private func commonInit() { // 加载XIB的逻辑 let nib = UINib(nibName: "SettingsView", bundle: nil) if let nibView = nib.instantiate(withOwner: self).first as? UIView { nibView.frame = bounds nibView.autoresizingMask = [.flexibleWidth, .flexibleHeight] addSubview(nibView) } // 纯代码创建的话,在这里添加子控件和约束 } }
这样修改后,你的自定义View应该就能正常显示在控制器中了。
内容的提问来源于stack exchange,提问作者Chandler Long
相关产品推荐
相关产品推荐

