一个视图内AVPlayer层不调整大小的UIView帧的变化时(AVPlayer layer ins

2019-06-23 14:00发布

我有一个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内的小尺寸。

如果有人可以帮助,我会很感激的任何建议。

多谢你们。

Answer 1:

  playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFit;


Answer 2:

转换@苏冉的解决方案,斯威夫特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()

该层现在将遵循制约就像一个普通的层会做。 无需手动更改范围或大小。



Answer 3:

其实你不应该添加AVPlayer的层作为子层。 相反的,你应该使用下面的方法,在其中要显示AVPlayer视图的子类。

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

并使用以下行添加(组)选手层。

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

希望能帮助到你;-)



Answer 4:

最后,我通过重新添加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];


Answer 5:

您可以通过重写改变层的框架-layoutSubviews方法:

- (void)layoutSubviews
{
    [super layoutSubviews];
    self.playerLayer.frame = self.bounds;
}


Answer 6:

发现马可Santarossa一个伟大的文章,显示多种方法来固定。 https://marcosantadev.com/calayer-auto-layout-swift/

我用他的第一个建议复位viewDidLayoutSubViews()事件期间层帧。

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    playerLayer.frame = view.layer.bounds
}


Answer 7:

theDunc的回答并没有为我工作。 我发现了一个解决方案,更简单:我只是需要在不断变化的UIView之后调整AVPlayerLayer的框架:

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

在这篇博客中所说的那样,一个视图的框架也影响到它的层。

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

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



Answer 8:

第一步:检查出UIVIew.h的UIView的自动尺寸属性

@属性(非原子)UIViewAutoresizing autoresizingMask; //简单的调整大小。 默认值是UIViewAutoresizingNone

此属性记者的“弹簧和支柱”,在IB控制,但它会带你进行一些试验,以得到你想要的结果。



Answer 9:

要到playerLayer ,您通过需要循环videoHolderView.layer.sublayers和更改每一个。

这是我在雨燕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
    }
}


Answer 10:

我在雨燕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)
}


Answer 11:

任何一个搜索Xamarin版本,因为我正在寻找

不添加AVPlayerLayer如子,但设置层Avplayer层

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

下面的行设置的层

(this.Layer as AVPlayerLayer).Player = _player;   // Acplayer


Answer 12:

对于那些你谁是只关注设备旋转过程中调整的AVPlayer,你可以改变在viewWillTransition您层帧(尺寸:CGSize,有协调: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)
}

这将在旋转过程中的所有其他视图沿动画的层框架。



文章来源: AVPlayer layer inside a view does not resize when UIView frame changes