Вопрос по avplayer, uiview, objective-c – Слой AVPlayer внутри представления не изменяется при изменении кадра UIView

47

у меня естьUIView который содержитAVPlayer показать видео. При смене ориентации мне нужно изменить размер и местоположение видео.

Я не очень разбираюсь в изменении размеров слоев, поэтому у меня возникают проблемы с изменением размера видео.

Я начинаю с созданияAVPlayer и добавление его проигрывателя в мой слой videoHolderView:

<code>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;
</code>

Затем на более позднем этапе я изменяю размер и расположение фрейма videoHolderView:

<code>[videoHolderView setFrame:CGRectMake(0, 0, 768, 502)];
</code>

На данный момент, мне нужно, чтобы avPlayer изменил размеры до тех же размеров. Это не происходит автоматически - avPlayer остается с его небольшим размером в videoHolderView.

Если кто-то может помочь, я буду очень признателен за любой совет.

Спасибо, парни.

Ваш Ответ

12   ответов
59
  playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFit;
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
AVLayerVideoGravityResizeAspectFitError: User Rate Limit ExceededAVLayerVideoGravityResizeAspect
20

Преобразование решения @ Suran's в Swift 3:

Сначала создайте класс, наследующий UIView, где вы переопределяете только 1 переменную:

import UIKit
import AVFoundation

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

Затем добавьте простой UIView с помощью построителя интерфейса и измените его класс на тот, который вы только что создали: AVPlayerView

change class of regular UIView to 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()

Теперь слой будет следовать ограничениям, как обычный слой. Нет необходимости вручную изменять границы или размеры.

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
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.a,vPlayer];
playerLayer.frame = videoHolderView.bounds;
[videoHolderView.layer addSublayer:playerLayer];
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
6

Вы можете изменить кадр слоя, переопределив-layoutSubviews метод:

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

Для тех из вас, кто занимается только изменением размера 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)
}

Это оживит ваш слой слоя вместе со всеми другими видами во время вращения.

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
    }
}
1

У меня была эта проблема в Swift 2.3, и я решил написать правильный класс PlayerView и установить его как subview:

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)
}
Error: User Rate Limit ExceededAVLayerVideoGravityResize
2

ответ Данка у меня не сработал. Я нашел более простое решение: мне просто нужно было отрегулировать фрейм AVPlayerLayer после его изменения в UIView:

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

Вэтот блог указано, что кадр вида также влияет на слой в нем.

When you change a view’s frame, it’s simply changing the layer’s frame.

Для этого случая это не так.

Error: User Rate Limit Exceeded
4

в которой показано несколько подходов к исправлению.https://marcosantadev.com/calayer-auto-layout-swift/

Я использовал его первое предложение для сброса фрейма слоя во время события viewDidLayoutSubViews ().

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    playerLayer.frame = view.layer.bounds
}
Error: User Rate Limit Exceeded
20

Фактически, вы не должны добавлять слой AVPlayer в качестве подслоя. Вместо этого вы должны использовать следующий метод в подклассе представления, в котором вы хотите отобразить AVPlayer.

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

И используйте следующую строку, чтобы добавить (установить) слой игрока.

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

Надеюсь, поможет;-)

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
1

Первый шаг: проверьте свойство автоматического изменения размера UIView в UIVIew.h

@property(nonatomic) UIViewAutoresizing autoresizingMask; // simple resize. default is UIViewAutoresizingNone

Это свойство соответствует «пружинам и стойкам» контроль в IB, хотя вам потребуются некоторые эксперименты, чтобы получить желаемые результаты.

Error: User Rate Limit Exceeded
Error: User Rate Limit ExceededAVPlayerLayer* playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer]; playerLayer.frame = videoHolderView.bounds;Error: User Rate Limit Exceeded theDuncs
Error: User Rate Limit Exceeded theDuncs
Error: User Rate Limit Exceeded theDuncs
Error: User Rate Limit Exceeded
0

Любой, кто ищет версию Xamarin, как я искал

не добавляйте AVPlayerLayer в качестве подслоя, но установите для слоя значение Avplayer Layer

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

Следующая строка устанавливает слой

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

Похожие вопросы