如何修改CustomVideoPlayer实现AVPlayer控件初始显示且支持点击切换显隐
问题描述
SpecificMediaFileView是用户点击按钮后弹出的视图,可展示图片或视频。当展示视频时,用户无法直观看到播放控件,需手动点击才会显示,以此知晓当前媒体为视频类型:
import SwiftUI import AVKit struct Media: Identifiable { let id = UUID() let creationTime: Date var image: UIImage? var videoURL: URL? } struct SpecificMediaFileView: View { let media: Media var body: some View { Group { if let image = media.image { Image(uiImage: image) } else if let videoURL = media.videoURL { VideoPlayer(player: AVPlayer(url: videoURL)) } } } }
我尝试了一种方案,让SpecificMediaFileView加载视频时初始显示播放控件,但此后无法通过点击手势手动隐藏或显示控件:
struct SpecificMediaFileView: View { let media: Media var body: some View { Group { if let image = media.image { Image(uiImage: image) } else if let videoURL = media.videoURL { CustomVideoPlayer(url: videoURL) } } } } struct CustomVideoPlayer: UIViewControllerRepresentable { var url: URL func makeUIViewController(context: Context) -> AVPlayerViewController { let controller = AVPlayerViewController() controller.player = AVPlayer(url) controller.showsPlaybackControls = true controller.setValue(false, forKey: "canHidePlaybackControls") return controller } func updateUIViewController(_ uiViewController: AVPlayerViewController, context: Context) { // Update the controller if needed. } }
第一种实现方案中,控件不会初始显示但支持点击切换显隐;第二种方案则完全相反。请问如何修改CustomVideoPlayer,实现播放控件初始显示且支持点击手势切换显隐?
解决方案
问题核心在于controller.setValue(false, forKey: "canHidePlaybackControls")这行代码,它强制禁用了播放控件的隐藏功能。我们需要保留原生的显隐切换逻辑,同时让控件初始状态为显示。
方案一:利用公开API状态切换(稳定安全)
通过先隐藏再重新显示控件的方式,触发初始显示效果,全程使用公开API,无被拒风险:
struct CustomVideoPlayer: UIViewControllerRepresentable { var url: URL class Coordinator: NSObject, AVPlayerViewControllerDelegate { // 视图加载完成后触发控件显隐切换,实现初始显示 func playerViewControllerDidEndDismissalTransition(_ playerViewController: AVPlayerViewController) { playerViewController.showsPlaybackControls = false playerViewController.showsPlaybackControls = true } } func makeCoordinator() -> Coordinator { Coordinator() } func makeUIViewController(context: Context) -> AVPlayerViewController { let controller = AVPlayerViewController() let player = AVPlayer(url: url) controller.player = player controller.showsPlaybackControls = true controller.delegate = context.coordinator return controller } func updateUIViewController(_ uiViewController: AVPlayerViewController, context: Context) { // 如需更新播放器逻辑,可在此处理 } }
方案二:调用私有API快速唤起(需注意风险)
直接调用AVPlayerViewController的私有方法唤起控件,实现更快的初始显示,但依赖私有API,苹果可能在后续iOS版本中修改或移除,存在审核被拒风险:
struct CustomVideoPlayer: UIViewControllerRepresentable { var url: URL func makeUIViewController(context: Context) -> AVPlayerViewController { let controller = AVPlayerViewController() let player = AVPlayer(url: url) controller.player = player controller.showsPlaybackControls = true // 延迟触发私有方法唤起控件 DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { controller.perform(Selector(("showPlaybackControls"))) } return controller } func updateUIViewController(_ uiViewController: AVPlayerViewController, context: Context) { // 更新逻辑 } }
说明
两种方案都保留了原生的点击显隐控件功能,因为没有修改canHidePlaybackControls属性。优先推荐方案一,稳定性和安全性更高。
内容的提问来源于stack exchange,提问作者swiftenjoyer
相关产品推荐
相关产品推荐

