iOS 13下UITableViewController模拟状态栏背景视图无法移除求助
问题排查与解决方案
先帮你拆解下代码里的核心问题,以及对应的修复方案:
1. 重复添加视图导致残留
你的setupStatusBarView在viewDidLayoutSubviews里调用,而这个方法会被频繁触发(比如滚动表格、屏幕旋转、视图布局更新时),每次调用都会新建一个statusBarView并添加到window上。这就导致window上堆积了多个tag=1的视图,你在viewWillDisappear里只移除了其中一个,剩下的自然会残留。
2. 依赖window查找视图不可靠
在iOS 13+的多场景架构下,UIApplication.shared.windows.first不一定能拿到当前活跃的window;而且通过tag查找视图本身就容易出错,尤其是在重复添加同tag视图的场景下。
3. 视图层级选择不合理
把状态栏背景视图挂到window上,脱离了当前控制器的视图层级,控制器销毁时不会自动清理这个视图,必须手动处理,增加了出错的概率。
修正后的代码方案
我们可以把状态栏视图绑定到当前控制器的视图层级,并且只创建一次,同时保留引用以便精准移除:
// 用属性保存状态栏视图的引用,避免重复创建和查找 private var statusBarBackgroundView: UIView? override func viewDidLoad() { super.viewDidLoad() // 只在viewDidLoad中初始化一次,避免重复创建 setupStatusBarView() } override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() // 仅更新视图布局,不重复创建 updateStatusBarViewFrame() } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) navigationController?.navigationBar.isHidden = true // 通过直接引用移除视图,精准可靠 statusBarBackgroundView?.removeFromSuperview() statusBarBackgroundView = nil } // MARK: - Setup Status Bar View private func setupStatusBarView() { let statusBarHeight = view.window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0 let statusBarView = UIView() statusBarView.backgroundColor = .systemBackground // 将视图插入到当前控制器view的最底层,避免遮挡表格内容 view.insertSubview(statusBarView, at: 0) statusBarBackgroundView = statusBarView } private func updateStatusBarViewFrame() { guard let statusBarView = statusBarBackgroundView else { return } let statusBarHeight = view.window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0 // 根据当前视图的 bounds 更新frame,适配屏幕旋转 statusBarView.frame = CGRect(x: 0, y: 0, width: view.bounds.width, height: statusBarHeight) }
额外优化建议
如果你的导航栏是随滚动自动隐藏的,可以在scrollViewDidScroll方法里,根据导航栏的显示/隐藏状态,同步控制状态栏视图的显示或背景色,让视觉效果更统一。
这样修改后,既解决了视图无法移除的问题,也避免了重复创建视图的资源浪费,同时视图会随控制器销毁自动清理,更符合iOS的视图层级设计逻辑。
内容的提问来源于stack exchange,提问作者kAiN
相关产品推荐
相关产品推荐

