自定义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
相关产品推荐
相关产品推荐

