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

Posted

技术标签:

【中文标题】Swift - 如何根据视频播放器框架的大小动态调整 UIView 的大小【英文标题】:Swift - how to resize a UIView dynamically based on the size of a video player frame 【发布时间】:2019-05-31 06:12:13 【问题描述】:

我有一个视频播放器和覆盖它的UIView,我在视频区域中用于Gesture Recognition。我这样做是为了让您可以点击视频的不同区域来播放、倒带和执行其他功能。

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

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

下面的代码可以直接复制到项目中播放视频并显示我要调整的UIView。您只需将UIView 添加到UIViewController 故事板。该代码不包含 GestureRecogniser 部分。

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() 中的框架,但也没有任何改变。我知道我的 updateTapRegions 函数不是正确的方法,但如果有人能指出我正确的方向,那将非常感谢。

【问题讨论】:

"但是我不知道如何访问视频播放器的 NSLayout 锚点" 因为视频播放器是一个层,而不是一个视图。它没有布局锚。你需要的是一个在我们旋转时改变大小的超级视图;然后必须使播放器层和手势视图都进行布局以响应该更改。 【参考方案1】:

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

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

【讨论】:

【参考方案2】:

最后,我通过将代码从转换函数(即使视频播放器正确调整大小)移动到 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)
    

【讨论】:

以上是关于Swift - 如何根据视频播放器框架的大小动态调整 UIView 的大小的主要内容,如果未能解决你的问题,请参考以下文章

在 Swift 3 中创建具有自定义大小的 VideoPlayer

如何根据swift 4或5中的图像大小使图像视图高度和宽度(纵横比)动态? [关闭]

如何在Swift中叠加视频上的动态标签?

Swift UITextField:在自动布局中创建一个动态减小的 UITextField 框架

Android动态的设置5图或1视频,并播放或浏览图片

如何根据内容动态调整 Twitter Bootstrap 模式的大小