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中的图像大小使图像视图高度和宽度(纵横比)动态? [关闭]