Подтвердить что ты не робот

Уровень AVPlayer внутри представления не изменяется при изменении рамок UIView

У меня есть 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 остается в этом небольшом размере в видеохолдинге.

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

Спасибо, ребята.

4b9b3361

Ответ 1

В конце концов я решил это, повторно добавив AVPlayerLayer в UIView. Я не уверен, почему смена рамки удалила слой, но это произошло. Здесь окончательное решение:

//amend the frame of the view
[videoHolderView setFrame:CGRectMake(0, 0, 768, 502)];

//reset the layer frame, and re-add it to the view
AVPlayerLayer* playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer];
playerLayer.frame = videoHolderView.bounds;
[videoHolderView.layer addSublayer:playerLayer];

Ответ 2

  playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFit;

Ответ 3

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

Сначала создайте класс, наследующий 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()

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

Ответ 4

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

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

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

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

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

Ответ 5

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

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

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

Ответ 6

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

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

Ответ 7

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

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

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

Когда вы меняете рамку представлений, просто меняя рамку слоев.

В этом случае это неверно.

Ответ 8

У меня была эта проблема в 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)
}

Ответ 9

Первый шаг: проверьте свойство URIiew autoresizing в UIVIew.h

@property (неатомный) UIViewAutoresizing autoresizingMask;//простое изменение размера. default - UIViewAutoresizingNone

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

Ответ 10

Чтобы добраться до 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
    }
}

Ответ 11

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

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

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

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

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

Ответ 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)
}

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

Ответ 13

В Swift 4 используйте

    playerLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill

или любое другое свойство AVLayerVideoGravity, которое вы пожелаете.