Swift iOS:Container View被右侧导航栏按钮遮挡,置顶代码无效求助
这个问题我之前也踩过坑!核心原因是你的自定义Container View的父视图层级不对:如果直接把它添加到当前ViewController的self.view上,导航栏(包括右侧的铃铛图标)属于UINavigationController的视图层级,它的z-order比self.view更高,所以你调用self.view.bringSubview(toFront:myCustomView)只能在self.view的子视图范围内调整层级,根本碰不到导航栏的层级,自然无法让自定义View显示在顶层。
下面给你几个靠谱的解决方案,按推荐程度排序:
方案1:将自定义View添加到导航控制器的视图层级中(最推荐)
把你的自定义Container View添加到UINavigationController的view上,这样两者就处于同一个父视图层级了,再调用bringSubview(toFront:)就能生效:
// 先将自定义View添加到导航控制器的view上 self.navigationController?.view.addSubview(myCustomView) // 调整层级到最顶层 self.navigationController?.view.bringSubview(toFront: myCustomView)
这个方法操作简单,而且不需要额外管理窗口,稳定性最高。
方案2:将自定义View添加到Key Window上
如果你的自定义View需要覆盖整个屏幕(包括状态栏),可以把它添加到应用的Key Window上:
// iOS 13+ 适配场景的Key Window获取方式 if let keyWindow = UIApplication.shared.connectedScenes .filter({ $0.activationState == .foregroundActive }) .compactMap({ $0 as? UIWindowScene }) .first?.windows .first(where: { $0.isKeyWindow }) { keyWindow.addSubview(myCustomView) keyWindow.bringSubview(toFront: myCustomView) }
注意要确保你的自定义View的frame设置正确,避免布局偏移。
方案3:调整导航栏铃铛图标的层级
如果你不想改动自定义View的父视图,也可以把导航栏上的铃铛图标往层级后面挪:
// 假设铃铛是导航栏的右侧BarButtonItem if let bellCustomView = self.navigationItem.rightBarButtonItem?.customView { bellCustomView.superview?.sendSubview(toBack: bellCustomView) }
这个方法的缺点是需要准确找到铃铛对应的View,如果你的铃铛是系统自带的BarButtonItem(不是自定义View),可能需要遍历导航栏的子视图来查找,可靠性不如前两个方案。
方案4:使用独立UIWindow提升层级
创建一个独立的UIWindow,设置它的windowLevel比导航栏更高(导航栏的windowLevel是UIWindowLevelNavigation),把自定义View放在这个窗口里:
// 作为ViewController的属性持有,避免被释放 private var alertWindow: UIWindow? func showCustomNotificationView() { let window = UIWindow(frame: UIScreen.main.bounds) window.windowLevel = UIWindowLevelAlert // 比导航栏层级高 window.rootViewController = UIViewController() window.backgroundColor = .clear window.isHidden = false window.addSubview(myCustomView) // 这里记得给myCustomView设置正确的约束或frame myCustomView.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ myCustomView.topAnchor.constraint(equalTo: window.topAnchor, constant: 80), myCustomView.trailingAnchor.constraint(equalTo: window.trailingAnchor, constant: -16), myCustomView.widthAnchor.constraint(equalToConstant: 200), myCustomView.heightAnchor.constraint(equalToConstant: 100) ]) self.alertWindow = window }
这个方案适合需要全局覆盖的通知类视图,但要注意管理window的生命周期,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Vishaka Watal

