在窗口全屏展示新NSView后如何禁止访问下层所有NSView
问题原因分析
- 你当前的实现仅将登录视图添加到了内容控制器的视图层级中,既没有保证登录视图完全覆盖所有下层可交互区域,也没有拦截下层视图的触摸事件,才会出现下层视图仍可操作的问题。
修复方案
方案1:直接将登录视图添加到window层级(推荐,适配全窗口拦截)
这是最稳妥的全窗口拦截方案,代码如下:
let signInVC = SignInViewController() // 获取当前主窗口 guard let window = UIApplication.shared.windows.first(where: { $0.isKeyWindow }) else { return } // 设置登录视图尺寸和窗口完全一致,自动适配横竖屏变化 signInVC.view.frame = window.bounds signInVC.view.autoresizingMask = [.flexibleWidth, .flexibleHeight] // 加到window最顶层 window.addSubview(signInVC.view) // 持有登录控制器避免提前释放 window.rootViewController?.addChild(signInVC) signInVC.didMove(toParent: window.rootViewController)
补充说明:添加到window层级的视图默认位于所有内容控制器视图之上,只要登录视图不是完全透明,就会自动拦截所有下层触摸事件,不需要额外处理交互拦截逻辑。
方案2:模态弹出登录控制器(系统原生逻辑,实现最简单)
如果你的业务场景允许全屏模态的交互形式,直接用系统的present方法即可,系统会自动禁用下层交互:
let signInVC = SignInViewController() signInVC.modalPresentationStyle = .fullScreen // 设为全屏完全遮挡下层 self.present(signInVC, animated: true)
方案3:现有逻辑基础上补充交互拦截
如果你不想修改现有添加逻辑,只要给登录视图开启用户交互、保证撑满父视图即可修复:
let vc = SignInViewController() guard let parentView = self.view.window?.contentViewController?.view else { return } vc.view.frame = parentView.bounds vc.view.autoresizingMask = [.flexibleWidth, .flexibleHeight] vc.view.isUserInteractionEnabled = true // 显式开启登录视图的交互拦截 parentView.addSubview(vc.view) // 持有控制器避免提前释放 self.view.window?.contentViewController?.addChild(vc) vc.didMove(toParent: self.view.window?.contentViewController)
登录完成后的移除逻辑
登录成功后需要清理视图和控制器关联,避免内存泄漏:
signInVC.willMove(toParent: nil) signInVC.view.removeFromSuperview() signInVC.removeFromParent()
内容的提问来源于stack exchange,提问作者Kunj
相关产品推荐
相关产品推荐

