59

我有一个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 在 vi​​deoHolderView 中保持较小的尺寸。

如果有人可以提供帮助,我将非常感谢任何建议。

多谢你们。

4

13 回答 13

66
  playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFit;
于 2015-04-13T22:33:18.920 回答
37

将@Suran 的解决方案转换为 Swift:

首先,创建一个继承 UIView 的类,您只覆盖 1 个变量:

import UIKit
import AVFoundation

class AVPlayerView: UIView {
    override class var layerClass: AnyClass {
        return AVPlayerLayer.self
    }
}

然后使用界面生成器添加一个简单的 UIView 并将其类更改为您刚刚创建的类:AVPlayerView

将常规 UIView 的类更改为 AVPlayerView

然后,为该视图创建一个出口。称之为 avPlayerView

@IBOutlet weak var avPlayerView: AVPlayerView!

现在,您可以在 viewcontroller 中使用该视图并像这样访问它的 avlayer:

let avPlayer = AVPlayer(url: video)
let castLayer = avPlayerView.layer as! AVPlayerLayer
castLayer.player = avPlayer
avPlayer.play()

该层现在将像常规层一样遵循约束。无需手动更改边界或大小。

于 2017-01-16T18:03:22.200 回答
21

实际上,您不应该将 AVPlayer 的图层添加为子图层。取而代之的是,您应该在要显示 AVPlayer 的视图的子类中使用以下方法。

+ (Class)layerClass
{
     return [AVPlayerLayer class];
}

并使用以下行添加(设置)播放器层。

[(AVPlayerLayer *)self.layer setPlayer:self.avPlayer];

希望能帮助到你;-)

于 2015-01-26T14:01:51.073 回答
16

最后我通过将 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];
于 2012-04-17T17:21:24.190 回答
14

找到 Marco Santarossa 的一篇很棒的文章,其中展示了多种修复方法。https://marcosantadev.com/calayer-auto-layout-swift/

我使用他的第一个建议在 viewDidLayoutSubViews() 事件期间重置图层框架。

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    playerLayer.frame = view.layer.bounds
}
于 2017-08-02T12:06:35.703 回答
8

您可以通过覆盖以下-layoutSubviews方法来更改图层的框架:

- (void)layoutSubviews
{
    [super layoutSubviews];
    self.playerLayer.frame = self.bounds;
}
于 2015-10-10T22:11:47.807 回答
7

在 Swift 4 中使用

    playerLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill

AVLayerVideoGravity或您想要的任何财产。

于 2019-09-19T09:26:39.417 回答
3

theDunc 的回答对我不起作用。我找到了一个更简单的解决方案:我只需要在 UIView 中更改 AVPlayerLayer 的框架后调整它:

avPlayerLayer.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);

这篇博客中声明,视图的框架也会影响其中的层。

当您更改视图的框架时,它只是更改了图层的框架。

对于这种情况,这是不正确的。

于 2015-01-22T15:43:29.447 回答
2

我在 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)
}
于 2016-09-13T14:37:08.333 回答
1

第一步:在 UIVIew.h 中查看 UIView 的 autoresizing 属性

@property(nonatomic) UIViewAutoresizing autoresizingMask; // 简单的调整大小。默认是 UIViewAutoresizingNone

这个属性对应于 IB 中的“springs and struts”控件,尽管它需要你进行一些实验才能得到你想要的结果。

于 2012-04-12T15:14:41.177 回答
1

要到达playerLayer,您需要遍历videoHolderView.layer.sublayers并更改每一个。

这就是我在 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
    }
}
于 2016-07-20T22:32:14.640 回答
1

对于那些只关心在设备旋转期间调整 AVPlayer 大小的人,您可以在 viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) 方法中更改图层框架,如下所示。

//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)
}

这将在旋转期间为您的图层框架以及所有其他视图设置动画。

于 2018-05-21T01:54:59.933 回答
0

在我搜索时搜索 Xamarin 版本的任何人

不要将 AVPlayerLayer 添加为子图层,而是将图层设置为 Avplayer 图层

[Export("layerClass")]
public static Class LayerClass()
{
    return new Class(typeof(AVPlayerLayer));
}

以下行设置图层

(this.Layer as AVPlayerLayer).Player = _player;   // Acplayer
于 2016-08-13T18:01:44.943 回答