UIHostingController被UIPageViewController dismiss时未收到通知导致视频无法暂停的问题
UIHostingController被UIPageViewController dismiss时未收到通知导致视频无法暂停的问题
我之前也碰到过一模一样的坑!用UIPageViewController嵌套SwiftUI的UIHostingController做轮播时,切换页面后视频居然还在后台播放,查了半天才发现是生命周期回调的问题——UIPageViewController为了保持滑动流畅,会把非当前页面的控制器缓存起来,根本不会触发常规的viewWillDisappear/viewDidDisappear,而SwiftUI的onDisappear完全依赖这些UIKit的生命周期事件,所以视频播放器压根不知道自己被隐藏了。
给你分享几个亲测有效的解决方法:
方法一:自定义UIHostingController,手动传递消失事件
我们可以给UIHostingController加个钩子,在它的视图即将消失时主动通知SwiftUI视图暂停视频:
首先自定义一个HostingController子类:
class CustomHostingController<Content: View>: UIHostingController<Content> { // 定义一个闭包,用来传递消失事件 var onViewWillDisappear: (() -> Void)? override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) // 页面即将消失时触发闭包 onViewWillDisappear?() } // 可选:页面重新出现时恢复播放 var onViewWillAppear: (() -> Void)? override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) onViewWillAppear?() } }
然后在创建UIHostingController的时候,把暂停视频的逻辑传进去:
// 假设你的视频播放器视图是VideoPlayerView,里面有个ObservableObject管理播放状态 let videoModel = VideoModel(url: videoURL) let hostingVC = CustomHostingController(rootView: VideoPlayerView(model: videoModel)) // 绑定暂停逻辑 hostingVC.onViewWillDisappear = { videoModel.pause() } // 可选:绑定恢复播放逻辑 hostingVC.onViewWillAppear = { videoModel.play() }
方法二:利用UIPageViewController的代理监听页面切换
通过UIPageViewController的代理方法,在页面切换完成后,主动找到之前显示的控制器,触发暂停:
首先让你的UIPageViewController所在的类遵守UIPageViewControllerDelegate:
extension YourPageVC: UIPageViewControllerDelegate { func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) { // 确保切换完成,并且有之前的控制器 guard completed, let previousHostingVC = previousViewControllers.first as? CustomHostingController<VideoPlayerView> else { return } // 直接调用SwiftUI视图里的暂停方法 previousHostingVC.rootView.model.pause() } }
这里要注意:如果你的SwiftUI视图里的播放状态是私有变量,最好用@ObservedObject或者@Binding把暂停方法暴露出来,方便外部调用。
避坑提醒
- 别指望SwiftUI的
onDisappear能解决这个问题!UIPageViewController的缓存机制会让这个回调完全不触发,除非你把页面从控制器数组里移除,但那样会失去缓存,滑动起来会卡顿。 - 如果用方法一,记得同时处理
viewWillAppear的恢复逻辑,不然用户滑回来视频不会自动继续播,体验会很差。
我当时用的是方法一,把自定义HostingController和ObservableObject结合起来,完美解决了视频偷偷播放的问题,你可以根据自己的项目结构选合适的方案~
内容来源于stack exchange
相关产品推荐
相关产品推荐

