Swift中隐藏Presented视图时如何避免呈现控制器被隐藏
首先咱们来拆解下你遇到的问题:当你用present(_:animated:completion:)展示Djay.shared.PlayerView后,直接设置它的view.isHidden = true会连呈现方的视图也一起隐藏。这大概率是因为默认的modalPresentationStyle(比如.fullScreen)会让呈现方的视图被从窗口中移除或隐藏,当你把presented的视图也隐藏后,窗口上就没有可见的视图了,所以看起来呈现方的视图也消失了。
而你的核心需求是:保持PlayerView控制器存活(让音频持续播放),同时隐藏它的UI,之后还能重新显示,并且不影响呈现方的视图操作。下面给你几个可行的解决方案:
方案1:修改ModalPresentationStyle为OverFullScreen
这个方案不需要修改第三方库代码,只需要在present前调整presented控制器的模态展示样式:
// 先获取PlayerView实例,设置模态样式 let playerViewController = Djay.shared.PlayerView playerViewController.modalPresentationStyle = .overFullScreen // 如果需要防止用户通过下拉等操作误关闭控制器,加上这句 playerViewController.isModalInPresentation = true // 再进行present操作 present(playerViewController, animated: true, completion: nil)
之后你要隐藏它的UI时,直接设置view.isHidden就不会影响呈现方的视图了:
Djay.shared.PlayerView.view.isHidden = true
为什么这个方案有效?
.overFullScreen模式下,呈现方的视图会保留在窗口层级中,只是被presented的视图覆盖。当你隐藏presented的视图后,呈现方的视图就会重新显示出来,同时PlayerView控制器依然处于活跃状态,音频不会中断。
方案2:将PlayerView作为子控制器添加(更灵活)
如果你希望完全控制PlayerView的显示/隐藏,同时不依赖模态展示的层级限制,可以把它作为子控制器添加到呈现方中:
// 添加子控制器 let playerViewController = Djay.shared.PlayerView addChild(playerViewController) // 设置PlayerView的视图大小和呈现方一致(你可以根据需求调整frame) playerViewController.view.frame = self.view.bounds self.view.addSubview(playerViewController.view) playerViewController.didMove(toParent: self) // 隐藏UI时 playerViewController.view.isHidden = true // 重新显示时 playerViewController.view.isHidden = false
这个方案的优势:
- 完全避免了模态展示带来的层级问题,隐藏
PlayerView的视图只会影响它自己,不会牵连呈现方。 PlayerView控制器的生命周期和呈现方绑定,只要呈现方不被销毁,音频就会持续播放。- 你可以更灵活地调整
PlayerView的视图位置、大小,比如只在屏幕底部显示一小部分,隐藏时直接滑出屏幕等。
方案3:隐藏PlayerView内部的内容而非整个视图(如果能修改第三方库)
如果你有权限修改Djay的PlayerView代码,那最好的方式是给PlayerView添加一个专门的方法来隐藏内部内容,而不是直接隐藏整个视图:
// 在PlayerView控制器中添加方法 extension PlayerView { func togglePlayerVisibility() { // 假设playerContentView是承载播放器UI的容器视图 self.playerContentView.isHidden = !self.playerContentView.isHidden // 如果需要透明背景,可以同时设置背景色 self.view.backgroundColor = self.playerContentView.isHidden ? .clear : .black } }
之后你只需要调用这个方法来控制显示/隐藏:
Djay.shared.PlayerView.togglePlayerVisibility()
这种方式既不会影响外部视图,也能保证控制器的活跃状态,是最优雅的解决方案。
内容的提问来源于stack exchange,提问作者Zack117

