添加至UIApplication.keyWindow的视图在多层模态控制器下无法访问的解决问询
解决多层模态下全局视图的访问与显示问题
嘿,这个问题我之前帮不少开发者踩过坑——核心原因是iOS 13及以后的版本里,UIApplication.shared.keyWindow已经不是靠谱的全局窗口引用了。多场景支持加上新的模态呈现机制,多层模态后,当前活跃的窗口可能已经切换到模态窗口,你之前加到旧keyWindow的视图要么被遮挡,要么在新的控制器上下文里找不到。
下面给你两种针对性的解决方案,按需选择:
一、确保视图始终在最顶层显示
与其死磕旧的keyWindow,不如动态获取当前最活跃的顶层窗口,把你的myView加到这里:
1. 写个工具方法获取当前顶层窗口
我通常会给UIApplication加个扩展:
extension UIApplication { var currentKeyWindow: UIWindow? { if #available(iOS 15.0, *) { return connectedScenes .compactMap { $0 as? UIWindowScene } .flatMap { $0.windows } .first { $0.isKeyWindow } } else { return windows.first { $0.isKeyWindow } } } }
2. 替换原来的添加代码
把你之前的:
UIApplication.shared.keyWindow?.addSubview(myView)
改成:
UIApplication.shared.currentKeyWindow?.addSubview(myView)
这样不管你弹出多少层模态,myView都会被加到当前最顶层的窗口上,确保所有控制器都能看到它。
二、确保能在任何控制器中访问到myView实例
如果你的问题是在第二层模态控制器里找不到myView的引用(而不是视图被挡住),那你需要把myView做成全局可访问的实例:
1. 把myView设计成单例
class MyGlobalView: UIView { // 全局唯一实例 static let shared = MyGlobalView(frame: /* 你的布局frame */) // 私有化构造方法,避免重复创建 private init(frame: CGRect) { super.init(frame: frame) // 这里做你的视图初始化配置,比如样式、布局 setupView() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } private func setupView() { backgroundColor = .orange // 比如固定在屏幕顶部 frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 60) } }
2. 初始化并添加到窗口
在App启动或者需要显示的时候:
let globalView = MyGlobalView.shared UIApplication.shared.currentKeyWindow?.addSubview(globalView)
3. 在任意控制器中访问
不管是第几层模态控制器,直接通过单例就能拿到:
let myGlobalView = MyGlobalView.shared // 做你需要的操作,比如修改文本、隐藏/显示 myGlobalView.isHidden = false
额外小提示
- 如果你的模态样式是
UIModalPresentationStyle.fullScreen,它会替换当前窗口的rootViewController,但只要你把视图加到当前keyWindow,依然会在最顶层显示。 - 要是需要视图在模态弹出时依然能交互,记得设置
myView.isUserInteractionEnabled = true,必要时可以调用currentKeyWindow?.bringSubviewToFront(myView)确保它在最上层。
内容的提问来源于stack exchange,提问作者Hyder
相关产品推荐
相关产品推荐

