我有UIView
,其中包含AVPlayer
来显示视频。更改方向时,我需要更改视频的大小和位置。
我对调整图层大小没有经验,所以我在调整视频大小时遇到了问题。
首先创建AVPlayer
并将其播放器添加到我的videoHolderView图层:
NSURL *videoURL = [NSURL fileURLWithPath:videoPath];
self.avPlayer = [AVPlayer playerWithURL:videoURL];
AVPlayerLayer* playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer];
playerLayer.frame = videoHolderView.bounds;
playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;
playerLayer.needsDisplayOnBoundsChange = YES;
[videoHolderView.layer addSublayer:playerLayer];
videoHolderView.layer.needsDisplayOnBoundsChange = YES;
然后,稍后,我会更改videoHolderView框架的大小和位置:
[videoHolderView setFrame:CGRectMake(0, 0, 768, 502)];
此时,我需要avPlayer调整大小到这些相同的维度。这不会自动发生 - avPlayer在videoHolderView中保持小尺寸。
如果有人可以提供帮助,我真的很感激任何建议。
谢谢你们。
答案 0 :(得分:61)
playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFit;
答案 1 :(得分:23)
将@ Suran的解决方案转换为Swift 3:
首先,创建一个继承UIView的类,其中只覆盖1个变量:
import UIKit
import AVFoundation
class AVPlayerView: UIView {
override class var layerClass: AnyClass {
return AVPlayerLayer.self
}
}
然后使用界面构建器添加一个简单的UIView,并将其类更改为您刚刚创建的类:AVPlayerView
然后,为该视图制作一个出口。称之为avPlayerView
@IBOutlet weak var avPlayerView: AVPlayerView!
现在,您可以在viewcontroller中使用该视图并访问其avlayer,如下所示:
let avPlayer = AVPlayer(url: video)
let castedLayer = avPlayerView.layer as! AVPlayerLayer
castedLayer.player = avPlayer
avPlayer.play()
现在,图层将遵循约束,就像常规图层一样。无需手动更改边界或大小。
答案 2 :(得分:21)
实际上你不应该将AVPlayer的图层添加为子图层。而不应该使用以下方法,在要显示AVPlayer的视图的子类中。
+ (Class)layerClass
{
return [AVPlayerLayer class];
}
使用以下行添加(设置)播放器图层。
[(AVPlayerLayer *)self.layer setPlayer:self.avPlayer];
希望它有所帮助; - )
答案 3 :(得分:15)
最后,我通过将AVPlayerLayer重新添加到UIView来解决了这个问题。我不确定为什么更换框架会移除图层,但确实如此。这是最终的解决方案:
//amend the frame of the view
[videoHolderView setFrame:CGRectMake(0, 0, 768, 502)];
//reset the layer's frame, and re-add it to the view
AVPlayerLayer* playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer];
playerLayer.frame = videoHolderView.bounds;
[videoHolderView.layer addSublayer:playerLayer];
答案 4 :(得分:7)
您可以通过覆盖-layoutSubviews
方法来更改图层的框架:
- (void)layoutSubviews
{
[super layoutSubviews];
self.playerLayer.frame = self.bounds;
}
答案 5 :(得分:6)
发现一篇由Marco Santarossa撰写的精彩文章,展示了多种修复方法。 https://marcosantadev.com/calayer-auto-layout-swift/
我在viewDidLayoutSubViews()事件期间使用了他的第一个建议重置图层框架。
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
playerLayer.frame = view.layer.bounds
}
答案 6 :(得分:2)
avPlayerLayer.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
在this blog中声明,View的框架也会影响其中的图层。
当您更改视图的帧时,它只是更改图层的帧。
对于这种情况,事实并非如此。
答案 7 :(得分:1)
第一步:在UIVIew.h中查看UIView的自动调整属性
@property(nonatomic)UIViewAutoresizing autoresizingMask; //简单调整大小默认是UIViewAutoresizingNone
此属性记录了IB中的“弹簧和支柱”控件,但它会带您进行一些实验以获得您想要的结果。
答案 8 :(得分:1)
要转到playerLayer
,您需要循环浏览videoHolderView.layer.sublayers
并更改每个。{/ p>
这就是我在Swift 2.2中所做的。
if let sublayers = videoHolderView.layer.sublayers{
for layer in sublayers where layer is AVPlayerLayer{
layer.frame.size = ... // change size of the layer here
}
}
答案 9 :(得分:1)
我在Swift 2.3中遇到过这个问题,我解决了写一个合适的PlayerView类并将其设置为子视图的问题:
import UIKit
import AVKit
import AVFoundation
class PlayerPreviewView: UIView {
override class func layerClass() -> AnyClass {
return AVPlayerLayer.self
}
var player: AVPlayer? {
get {
return playerLayer.player
}
set {
playerLayer.player = newValue
}
}
var playerLayer: AVPlayerLayer {
return layer as! AVPlayerLayer
}
override init(frame: CGRect) {
super.init(frame: frame)
playerLayer.videoGravity = AVLayerVideoGravityResize
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
playerLayer.videoGravity = AVLayerVideoGravityResize
}
}
在呈现的ViewController中:
private func play(asset asset: AVURLAsset){
let playerItem = AVPlayerItem(asset: asset)
player = AVPlayer(playerItem: playerItem)
player?.actionAtItemEnd = .None
player?.muted = true
playerPreviewView = PlayerPreviewView(frame: CGRectZero)
view.addSubview(playerPreviewView)
playerPreviewView.player = player
playerPreviewView.translatesAutoresizingMaskIntoConstraints = false
view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[subview]-0-|", options: .DirectionLeadingToTrailing, metrics: nil, views: ["subview": playerPreviewView]))
view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-0-[subview]-0-|", options: .DirectionLeadingToTrailing, metrics: nil, views: ["subview": playerPreviewView]))
player?.play()
NSNotificationCenter.defaultCenter().addObserver(self,
selector: #selector(SplashScreenViewController.videoDidFinish),
name: AVPlayerItemDidPlayToEndTimeNotification,
object: nil)
}
答案 10 :(得分:1)
在Swift 4中使用
warning X3205: 'round': conversion from larger type to smaller, possible loss of data
或您想要的 playerLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
的任何属性。
答案 11 :(得分:0)
任何人在搜索Xamarin版本时都在搜索
不要将AVPlayerLayer添加为子图层,而是将图层设置为Avplayer图层
[Export("layerClass")]
public static Class LayerClass()
{
return new Class(typeof(AVPlayerLayer));
}
以下行设置图层
(this.Layer as AVPlayerLayer).Player = _player; // Acplayer
答案 12 :(得分:0)
对于那些只关心在设备旋转期间调整AVPlayer大小的人,可以在viewWillTransition中更改图层框架(使用协调器:UIViewControllerTransitionCoordinator来调整大小:CGSize),如下所示。
//Swift 4
//Method in UIViewController
//Variable definitions are:
//self.layer is the AVPlayerLayer
//self.videoPlayerView is the view that the AVPlayerLayer is the sublayer of
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
coordinator.animate(alongsideTransition: { context in
self.layer.layoutIfNeeded()
UIView.animate(
withDuration: context.transitionDuration,
animations: {
self.layer.frame = self.videoPlayerView.bounds
}
)
}, completion: nil)
}
这将在旋转过程中为您的图层框架以及所有其他视图设置动画。