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

自定义MediaPlayerView跳转AVPlayerViewController报错,如何解决?

解决AVPlayerViewController Present失败的问题

这个错误的核心原因是你直接尝试用rootViewController(也就是你的MainTabBarController)来present播放器,但此时这个TabBarController的视图可能并没有处于窗口的层级结构中(或者当前活跃的是它的子控制器TagViewController)。正确的做法是找到你的MediaPlayerView所在的那个TagViewController,再用它来present。

第一步:给UIView添加扩展,获取所在的ViewController

我们可以通过遍历视图的响应链,找到它所属的ViewController。在你的项目里添加这个扩展:

extension UIView {
    func findParentViewController() -> UIViewController? {
        var responder: UIResponder? = self
        while responder != nil {
            responder = responder?.next
            if let viewController = responder as? UIViewController {
                return viewController
            }
        }
        return nil
    }
}

第二步:修改tapDetected方法,使用找到的父控制器

把原来的self.window?.rootViewController?.present替换成我们刚获取到的父控制器。同时要做好可选值的安全处理:

@objc func tapDetected() {
    print("tap!")
    guard let mediaURL = self.mediaURL else { return }
    
    let player = AVPlayer(url: mediaURL)
    let controller = AVPlayerViewController()
    controller.player = player
    
    // 获取当前视图所在的ViewController
    guard let parentVC = self.findParentViewController() else {
        print("无法找到父控制器")
        return
    }
    
    // 如果需要确保是TagViewController,可以加个判断
    if let tagVC = parentVC as? SweatNet.TagViewController {
        tagVC.present(controller, animated: true) {
            player.play()
        }
    } else {
        //  fallback:如果找不到TagVC,尝试用父控制器直接present
        parentVC.present(controller, animated: true) {
            player.play()
        }
    }
}

为什么这样能解决问题?

因为你的MediaPlayerView是放在TagViewController里的cell中的,通过响应链遍历,我们能准确找到这个视图所属的TagViewController,而这个控制器的视图肯定是处于当前窗口层级中的,所以present操作就能正常执行了。

另外,额外提两个小建议:

  • 在determineMediaType()方法里,pathExtention!是强制解包,建议改成可选绑定,避免url为nil时崩溃:
    func determineMediaType() {
        guard let url = self.mediaURL, let pathExtension = url.pathExtension else { return }
        if videoExtensions.contains(pathExtension) {
            print("Movie URL: \(url)")
            setupVideo(url: url)
        } else {
            print("Image URL: \(url)")
            setupImage(url: url)
        }
    }
    
  • 在setupVideo里,UIImage(named: "Play Triangle")也建议做可选绑定,防止图片不存在时崩溃。

内容的提问来源于stack exchange,提问作者BigBoy1337

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 04:15:51