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

SwiftUI中AVPlayer视图适配视频内容尺寸(消除全屏红色背景)

解决方法

步骤1:获取视频原生宽高比

先实现一个工具函数,从AVPlayer的资源中提取视频的宽高比例,这是让视图匹配视频尺寸的核心依据:

func getVideoAspectRatio(for player: AVPlayer) -> CGFloat? {
    guard let asset = player.currentItem?.asset else { return nil }
    return asset.tracks(withMediaType: .video).first.flatMap { track in
        let size = track.naturalSize.applying(track.preferredTransform)
        return abs(size.width / size.height)
    }
}

步骤2:修改VideoPlayerUIView适配动态尺寸

调整UIViewControllerRepresentable的实现,取消强制全屏的设置,同时监听视频资源变化来同步宽高比:

struct VideoPlayerUIView: UIViewControllerRepresentable {
    let player: AVPlayer
    @Binding var aspectRatio: CGFloat?

    func makeUIViewController(context: Context) -> UIViewController {
        let controller = UIViewController()
        let playerLayer = AVPlayerLayer(player: player)
        
        playerLayer.videoGravity = .resizeAspect
        playerLayer.frame = controller.view.bounds
        controller.view.layer.addSublayer(playerLayer)
        
        // 监听视频资源变化,更新宽高比
        player.addObserver(context.coordinator, forKeyPath: "currentItem", options: .new, context: nil)
        
        return controller
    }
    
    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
        guard let playerLayer = uiViewController.view.layer.sublayers?.first as? AVPlayerLayer else { return }
        playerLayer.player = player
        playerLayer.frame = uiViewController.view.bounds
        
        // 同步最新宽高比
        aspectRatio = getVideoAspectRatio(for: player)
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    class Coordinator: NSObject {
        let parent: VideoPlayerUIView
        
        init(_ parent: VideoPlayerUIView) {
            self.parent = parent
        }
        
        override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
            if keyPath == "currentItem" {
                parent.aspectRatio = getVideoAspectRatio(for: parent.player)
            }
        }
    }
    
    static func dismantleUIViewController(_ uiViewController: UIViewController, coordinator: Coordinator) {
        parent.player.removeObserver(coordinator, forKeyPath: "currentItem")
    }
}

步骤3:在SwiftUI视图中约束尺寸

在展示视频的父视图里,用获取到的宽高比约束视频视图的尺寸,这样红色背景就只会包裹视频内容:

struct ContentView: View {
    let player1 = AVPlayer(url: URL(string: "你的视频URL")!)
    @State private var videoAspectRatio: CGFloat?
    
    var body: some View {
        VideoPlayerUIView(player: player1, aspectRatio: $videoAspectRatio)
            .background(.red)
            .aspectRatio(videoAspectRatio, contentMode: .fit)
    }
}

关键说明

  • 取消了playerLayer.frame = UIScreen.main.bounds的强制全屏设置,让视图尺寸由视频比例决定
  • 通过@Binding传递宽高比,配合.aspectRatio修饰符约束视图大小,消除多余的红色填充
  • 添加观察者监听视频资源切换,确保宽高比能实时更新

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 20:13:14