如何在所有.xib ViewController中实现Global View始终可见?
实现全局始终可见的Global View方案
问题说明
想要创建一个“Global View”,使其在应用内任意.xib对应的ViewController中始终可见。目前将该视图插入第一个ViewController的.xib中,但切换到其他ViewController时视图会消失,不确定是否应该将其放入AppDelegate中。
用户提供的现有代码:
import UIKit class MonitoringViewController: UIViewController { @IBOutlet var contentView: UIView! @IBOutlet weak var viewForTab: UIView! override func viewDidLoad() { super.viewDidLoad() } @IBAction func buttonTab1(_ sender: UIButton) { } @IBAction func buttonTab2(_ sender: UIButton) { delegate?.navigateToAlertViewController() let alert = AlertViewController(nibName: "AlertViewController", bundle: nil) contentView.addSubview(alert.view) alert.didMove(toParent: self) } @IBAction func buttonTab3(_ sender: UIButton) { } }
核心问题原因
当前做法导致视图消失的本质是:每个ViewController的view是独立的视图层级容器,切换页面时原ViewController的view会被从屏幕视图树中移除,依附在它上面的GlobalView自然也会跟着消失。
可行解决方案
方案1:借助UIWindow添加全局视图(推荐iOS13+)
直接将GlobalView添加到应用主窗口,使其独立于所有ViewController的视图层级,始终保持可见。
步骤:
- 定义GlobalView类(支持代码创建或xib加载):
class GlobalView: UIView { // 代码初始化方式 init() { super.init(frame: .zero) // 自定义样式示例:顶部半透明提示栏 backgroundColor = UIColor.systemBlue.withAlphaComponent(0.8) translatesAutoresizingMaskIntoConstraints = false } // xib加载时的初始化方法 required init?(coder: NSCoder) { super.init(coder: coder) } }
- 在
SceneDelegate中添加全局视图(iOS13及以后用SceneDelegate,iOS12及以前可在AppDelegate的didFinishLaunchingWithOptions中处理):
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = (scene as? UIWindowScene) else { return } let window = UIWindow(windowScene: windowScene) let rootVC = MonitoringViewController(nibName: "MonitoringViewController", bundle: nil) window.rootViewController = rootVC window.makeKeyAndVisible() // 添加全局视图 let globalView = GlobalView() window.addSubview(globalView) // 设置约束:固定在顶部安全区 NSLayoutConstraint.activate([ globalView.topAnchor.constraint(equalTo: window.safeAreaLayoutGuide.topAnchor), globalView.leadingAnchor.constraint(equalTo: window.leadingAnchor), globalView.trailingAnchor.constraint(equalTo: window.trailingAnchor), globalView.heightAnchor.constraint(equalToConstant: 44) ]) // 确保全局视图在最上层 window.bringSubviewToFront(globalView) }
方案2:基于基类ViewController实现
创建所有ViewController的父类,在父类中统一添加GlobalView,确保每个页面都自带该视图。
步骤:
- 创建基类
BaseViewController:
class BaseViewController: UIViewController { private var globalView: GlobalView! override func viewDidLoad() { super.viewDidLoad() setupGlobalView() } private func setupGlobalView() { globalView = GlobalView() view.addSubview(globalView) // 设置约束:固定在顶部 NSLayoutConstraint.activate([ globalView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), globalView.leadingAnchor.constraint(equalTo: view.leadingAnchor), globalView.trailingAnchor.constraint(equalTo: view.trailingAnchor), globalView.heightAnchor.constraint(equalToConstant: 44) ]) // 确保视图在当前VC所有子视图的最上层 view.bringSubviewToFront(globalView) } }
- 让所有业务ViewController继承该基类:
class MonitoringViewController: BaseViewController { @IBOutlet var contentView: UIView! @IBOutlet weak var viewForTab: UIView! override func viewDidLoad() { super.viewDidLoad() // 基类已处理全局视图,无需重复设置 } @IBAction func buttonTab2(_ sender: UIButton) { delegate?.navigateToAlertViewController() let alert = AlertViewController(nibName: "AlertViewController", bundle: nil) addChild(alert) contentView.addSubview(alert.view) alert.view.frame = contentView.bounds alert.didMove(toParent: self) } // 其他按钮方法... }
不推荐直接放在AppDelegate中的原因
iOS13+已用SceneDelegate管理窗口生命周期,直接在AppDelegate中处理全局视图会引发适配问题;同时将视图逻辑放在AppDelegate中违反单一职责原则,不利于代码维护。
内容的提问来源于stack exchange,提问作者iosSwift
相关产品推荐
相关产品推荐

