You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 13:09:41