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

如何修改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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 19:07:11