Ios Swift-如何根据视频播放器帧的大小动态调整UIView的大小

Ios Swift-如何根据视频播放器帧的大小动态调整UIView的大小,ios,swift,uiview,avfoundation,avplayer,Ios,Swift,Uiview,Avfoundation,Avplayer,我有一个视频播放器,上面有一个ui视图,用于视频区域的手势识别。我这样做是为了让你可以点击视频的不同区域来播放、回放和执行其他功能 目前,这在横向效果很好,但如果我将设备旋转到纵向效果。ui视图不会调整大小,但视频播放器会调整大小。我试图以编程方式使用约束,但我不知道如何访问视频播放器的NSLayout锚 我有一个检索视频帧大小的函数,我当前使用该函数将UIView设置为视频播放器的大小 下面的代码可以复制到项目中,播放视频并显示我要调整的ui视图。您只需将UIView添加到UIViewCont

我有一个视频播放器,上面有一个
ui视图
,用于视频区域的
手势识别
。我这样做是为了让你可以点击视频的不同区域来播放、回放和执行其他功能


目前,这在横向效果很好,但如果我将设备旋转到纵向效果。
ui视图
不会调整大小,但视频播放器会调整大小。我试图以编程方式使用约束,但我不知道如何访问视频播放器的
NSLayout

我有一个检索视频帧大小的函数,我当前使用该函数将
UIView
设置为视频播放器的大小

下面的代码可以复制到项目中,播放视频并显示我要调整的
ui视图。您只需将
UIView
添加到
UIViewController
情节提要。代码不包含手势识别器部分

import UIKit
import AVFoundation

class ViewController: UIViewController {

let controlContainerView: UIView = {
    let view = UIView()
    view.backgroundColor = UIColor(white: 0, alpha: 1)
    return view
}()

let activityIndicatorView: UIActivityIndicatorView = {
    let aiv = UIActivityIndicatorView(style: .whiteLarge)
    aiv.translatesAutoresizingMaskIntoConstraints = false
    aiv.startAnimating()
    return aiv
}()

@IBOutlet weak var videoContainer: UIView!
var player: AVPlayer?
var playerLayer: AVPlayerLayer?
var tapRegionBounds: UIView!
var tapRegionAreaCreated: Bool = false

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.
    let urlString = "https://www.radiantmediaplayer.com/media/bbb-360p.mp4"
    videoPlayer(filename: urlString)
    player?.addObserver(self, forKeyPath: "currentItem.loadedTimeRanges", options: .new, context: nil)

}

override func viewDidAppear(_ animated: Bool) {
    self.playerLayer?.frame = CGRect(x: 0, y: 0, width: self.videoContainer.frame.width, height: self.videoContainer.frame.height)
    updateTapRegions()
}

func videoPlayer(filename: String){
    let item = AVPlayerItem(url: URL(string: filename)!)
    player = AVPlayer(playerItem: item)
    playerLayer = AVPlayerLayer(player: player)
    playerLayer?.videoGravity = .resizeAspect
    playerLayer?.frame = CGRect(x: 0, y: 0, width: self.videoContainer.frame.width, height: self.videoContainer.frame.height)
    videoContainer.layer.addSublayer(playerLayer!)
    player?.play()
}


override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if keyPath == "currentItem.loadedTimeRanges" {
        activityIndicatorView.stopAnimating()
        controlContainerView.backgroundColor = .clear
    }
}

func videoFrame() -> CGRect? {
    guard let layer = playerLayer
        else { return nil }
    let frame = layer.videoRect
    if frame.height > 0.0 {
        let frameInWindow = layer.convert(frame, to: nil)
        return view.convert(frameInWindow, from: nil)
    } else {
        return nil
    }
}

//THE CODE BELOW KIND OF WORKS TO SHOW HOW I WANT IT TO WORK BUT WITHOUT HAVING TO DELETE THE VIEW EACH TIME
func updateTapRegions() {
    guard let video = videoFrame() else { return }
    let container = videoContainer.bounds

    if tapRegionAreaCreated == true {
        tapRegionBounds.removeFromSuperview()
        tapRegionAreaCreated = false
    }

    tapRegionBounds = UIView()
    tapRegionBounds.frame = CGRect(x: video.minX, y: video.minY, width: container.width, height: video.height)
    tapRegionBounds?.alpha = 0.5
    tapRegionBounds.backgroundColor = UIColor.red

    if tapRegionAreaCreated == false {
        view.addSubview(tapRegionBounds)
        tapRegionAreaCreated = true
    }
}

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)
    coordinator.animate(alongsideTransition: { (context) in
    }) { (context) in
        self.playerLayer?.frame = CGRect(x: 0, y: 0, width: self.videoContainer.frame.width, height: self.videoContainer.frame.height)
        self.updateTapRegions()
    }
}

}

我试图更新
viewWillLayoutSubviews()
中的帧,但也没有任何更改。我知道我的UpdatePregions函数不是正确的方法,但如果有人能给我指出正确的方向,那将是非常感谢的。

最后,我将代码从转换函数(即使视频播放器的大小正确调整)移动到viewDidLayoutSubviews,然后运行良好。此外,我不再需要在每次设备更改方向时创建和删除视图

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    self.playerLayer?.frame = CGRect(x: 0, y: 0, width: self.videoContainer.frame.width, height: self.videoContainer.frame.height)

    guard let video = videoFrame() else { return }

    if tapRegionBounds != nil {
         self.tapRegionBounds.frame = CGRect(x: video.minX, y: video.minY, width: video.width, height: video.height)
    }
}

不幸的是,您在问题中没有说明如何调整视频容器视图的大小,这一切都取决于此。但有一种可能性。我使用自动布局在纵向和横向中获得这些结果:


现在假设我们有一个子层(AVPlayerLayer)和一个子视图(点击手势视图)。嗯,可以使用autolayout自动调整子视图的大小以适应它!所以只剩下玩家层;它不会使用autolayout自动调整大小,但您可以在
viewDidLayoutSubviews

中手动调整大小“但我不知道如何访问视频播放器的NSLayout定位点”,因为视频播放器是一个层,而不是一个视图。它没有布局锚。你需要的是一个超级视图,当我们旋转时它会改变大小;然后,必须使播放器层和手势视图都进行布局,以响应该更改。