将AVPlayerViewController嵌入UIView时播放器错位问题求助
解决AVPlayerViewController视图超出嵌入UIView的问题
你遇到的问题主要出在直接添加AVPlayerViewController的view但未正确处理布局约束和子控制器生命周期上,下面是具体的原因和解决方案:
问题根源
- frame时机错误:在
viewDidLoad中,videoView的frame还没有经过AutoLayout的最终计算(此时的frame是Storyboard里的初始值,不是屏幕上实际的布局结果),直接设置smallVideoPlayerViewController.view.frame = videoView.frame会导致位置和尺寸错误。 - 缺少子控制器管理:你只是把AVPlayerViewController的view添加到了videoView上,但没有将它作为当前ViewController的子控制器,这会导致AVPlayerViewController的生命周期方法无法正常触发,进而引发布局异常。
正确解决方案(使用AVPlayerViewController嵌入)
修改你的viewDidLoad代码,按照添加子控制器+AutoLayout约束的方式来实现:
class ViewController: UIViewController { let smallVideoPlayerViewController = AVPlayerViewController() @IBOutlet weak var videoView: UIView! override func viewDidLoad() { super.viewDidLoad() let videoName = "test" guard let videoPath = Bundle.main.path(forResource: videoName, ofType: "mp4"), let videoUrl = URL(fileURLWithPath: videoPath) else { return } smallVideoPlayerViewController.showsPlaybackControls = false smallVideoPlayerViewController.player = AVPlayer(url: videoUrl) // 1. 将AVPlayerViewController添加为当前控制器的子控制器 addChild(smallVideoPlayerViewController) videoView.addSubview(smallVideoPlayerViewController.view) smallVideoPlayerViewController.didMove(toParent: self) // 2. 关闭自动调整mask,使用AutoLayout约束 smallVideoPlayerViewController.view.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ smallVideoPlayerViewController.view.topAnchor.constraint(equalTo: videoView.topAnchor), smallVideoPlayerViewController.view.leadingAnchor.constraint(equalTo: videoView.leadingAnchor), smallVideoPlayerViewController.view.trailingAnchor.constraint(equalTo: videoView.trailingAnchor), smallVideoPlayerViewController.view.bottomAnchor.constraint(equalTo: videoView.bottomAnchor) ]) smallVideoPlayerViewController.player?.play() } }
更轻量的替代方案(使用AVPlayerLayer)
如果你不需要AVPlayerViewController提供的额外功能(比如播放控制栏,你已经关闭了),直接使用AVPlayerLayer嵌入到videoView的layer中会更轻量,也能避免子控制器的问题:
class ViewController: UIViewController { private var player: AVPlayer? private var playerLayer: AVPlayerLayer? @IBOutlet weak var videoView: UIView! override func viewDidLoad() { super.viewDidLoad() let videoName = "test" guard let videoPath = Bundle.main.path(forResource: videoName, ofType: "mp4"), let videoUrl = URL(fileURLWithPath: videoPath) else { return } player = AVPlayer(url: videoUrl) playerLayer = AVPlayerLayer(player: player) guard let playerLayer = playerLayer else { return } // 设置视频填充模式,根据需求选择.resizeAspect或.resizeAspectFill playerLayer.videoGravity = .resizeAspect videoView.layer.addSublayer(playerLayer) player?.play() } // 在view布局更新时,同步更新playerLayer的尺寸 override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() playerLayer?.frame = videoView.bounds } }
额外注意事项
- 确保你的
videoView在Storyboard/XIB中已经设置了正确的AutoLayout约束(比如和父视图的边距、宽高比等),没有布局警告。 - 如果使用AVPlayerViewController,不要忘记调用
addChild和didMove(toParent:)方法,这是管理子控制器生命周期的必要步骤。
内容的提问来源于stack exchange,提问作者fnisi
相关产品推荐
相关产品推荐

