如何监听AVPlayer的控制栏可见性变化事件?
检测AVPlayer控制栏可见状态并适配旧机型导航需求
问题说明
视频播放页面需全屏展示,新款带滑动手势导航的iPhone可通过手势退出页面,但iPhone 6s/7等旧机型无此功能,因此需要在AVPlayer控制栏可见时显示导航栏返回按钮,核心需求是检测AVPlayer控制栏的可见状态。
解决方案
由于SwiftUI原生VideoPlayer未提供控制栏可见状态的公开API,我们可以通过自定义AVPlayerViewController子类结合UIViewRepresentable来实现状态监听,具体代码如下:
1. 自定义播放器控制器子类
import SwiftUI import AVKit class CustomPlayerViewController: AVPlayerViewController { // 控制栏状态变化回调 var controlsVisibilityChanged: ((Bool) -> Void)? private var autoHideTimer: Timer? override func viewDidLoad() { super.viewDidLoad() showsPlaybackControls = true // 添加点击手势监听屏幕点击事件 let tapGesture = UITapGestureRecognizer(target: self, action: #selector(toggleControls)) tapGesture.cancelsTouchesInView = false view.addGestureRecognizer(tapGesture) } @objc private func toggleControls() { let isVisible = playbackControlsView?.alpha == 1.0 controlsVisibilityChanged?(isVisible) // 模拟系统自动隐藏逻辑:显示控制栏后3秒无操作则隐藏 autoHideTimer?.invalidate() if isVisible { autoHideTimer = Timer.scheduledTimer(withTimeInterval: 3.0, repeats: false) { [weak self] _ in self?.controlsVisibilityChanged?(false) } } } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) autoHideTimer?.invalidate() } }
2. 封装为SwiftUI可用的View
struct PlayerContainerView: UIViewRepresentable { let videoURL: URL var onControlsVisibilityChange: ((Bool) -> Void)? func makeUIView(context: Context) -> UIView { let containerView = UIView(frame: .zero) let player = AVPlayer(url: videoURL) let playerVC = CustomPlayerViewController() playerVC.player = player playerVC.controlsVisibilityChanged = onControlsVisibilityChange playerVC.view.frame = containerView.bounds playerVC.view.autoresizingMask = [.flexibleWidth, .flexibleHeight] containerView.addSubview(playerVC.view) context.coordinator.playerVC = playerVC player.play() return containerView } func updateUIView(_ uiView: UIView, context: Context) {} func makeCoordinator() -> Coordinator { Coordinator() } class Coordinator { var playerVC: CustomPlayerViewController? deinit { playerVC?.player?.pause() } } }
3. 改造原播放页面
struct VideoPlayerView: View { let videoURL: URL @State private var controlsAreVisible = true @State private var pageTitle = "" var body: some View { PlayerContainerView(videoURL: videoURL) { isVisible in DispatchQueue.main.async { controlsAreVisible = isVisible } } .edgesIgnoringSafeArea(.all) .navigationBarBackButtonHidden(!controlsAreVisible) .navigationBarHidden(!controlsAreVisible) .navigationBarTitle(pageTitle, displayMode: .inline) .statusBar(hidden: !controlsAreVisible) .onChange(of: controlsAreVisible) { isVisible in pageTitle = isVisible ? videoURL.lastPathComponent : "" } } }
方案说明
- 通过自定义
AVPlayerViewController,添加点击手势监听用户操作,同步控制栏可见状态到SwiftUI的状态变量。 - 用定时器模拟系统控制栏的自动隐藏逻辑,确保状态同步的准确性。
- 根据控制栏状态动态切换导航栏返回按钮、导航栏和状态栏的显示,适配旧机型的退出需求。
内容的提问来源于stack exchange,提问作者user924
相关产品推荐
相关产品推荐

