设置透明背景后UINavigationController动画结束显示黑屏问题求助
我之前踩过完全一样的坑!你遇到的问题核心原因是:当把navigationController?.view.backgroundColor设为.clear后,导航控制器的view失去了不透明背景,而过渡动画完成后,导航控制器的视图层级里,前一个控制器的视图要么被隐藏、要么被导航控制器内部的私有视图挡住,最终露出了window默认的黑色背景。
下面是两种靠谱的解决方案,都是苹果允许的正规做法:
方案一:给半透明控制器添加模糊背景(推荐)
这种方式不需要修改导航控制器的任何配置,只需要在你的半透明控制器里添加模糊效果,就能自然看到前一个控制器的模糊内容,同时不会出现黑屏:
- 在半透明控制器的
viewDidLoad方法中,添加模糊效果视图作为底层:
override func viewDidLoad() { super.viewDidLoad() // 1. 创建模糊效果(可以根据需求选择不同样式,比如.systemMaterialLight) let blurEffect = UIBlurEffect(style: .systemUltraThinMaterialDark) let blurView = UIVisualEffectView(effect: blurEffect) blurView.frame = self.view.bounds blurView.autoresizingMask = [.flexibleWidth, .flexibleHeight] // 2. 把模糊视图放在view的最底层 self.view.insertSubview(blurView, at: 0) // 3. 设置控制器view的背景色为半透明(配合模糊效果增强层次感) self.view.backgroundColor = UIColor.black.withAlphaComponent(0.1) // 如果你需要让控制器内容整体半透明,保持你的原有设置 self.view.alpha = 0.9 }
- 确保导航栏的半透明属性开启(如果需要导航栏也半透明的话):
// 在push半透明控制器之前设置 navigationController?.navigationBar.isTranslucent = true navigationController?.navigationBar.backgroundColor = UIColor.clear.withAlphaComponent(0.5)
方案二:调整导航控制器视图层级(适合必须用导航控制器透明的场景)
如果你一定要让导航控制器的view透明,那需要确保前一个控制器的视图始终在导航控制器的view层级最底层,不会被挡住:
- 不要直接设置
navigationController?.view.backgroundColor = .clear,而是改为:
navigationController?.view.backgroundColor = .clear // 遍历子视图,把所有非自定义的视图背景设为透明 for subview in navigationController!.view.subviews { if subview.tag != 999 { // 标记我们后续可能添加的自定义背景视图 subview.backgroundColor = .clear } }
- 在半透明控制器的
viewDidAppear(_:)方法中,手动把前一个控制器的视图移到最底层:
override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) guard let navVC = navigationController, let previousVC = navVC.viewControllers.filter({ $0 != self }).last else { return } // 确保前一个控制器的视图在导航控制器view的最底层 navVC.view.insertSubview(previousVC.view, at: 0) }
- 记得在半透明控制器被pop的时候,移除前一个控制器的视图(避免重复添加):
override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) guard let navVC = navigationController, let previousVC = navVC.viewControllers.filter({ $0 != self }).last else { return } previousVC.view.removeFromSuperview() }
这种方式要注意视图层级的管理,避免出现重复视图或者布局混乱的问题,所以还是方案一更稳妥。
内容的提问来源于stack exchange,提问作者Bio-Matic
相关产品推荐
相关产品推荐

