webentwicklung-frage-antwort-db.com.de

Die Größe der AVPlayer-Ebene in einer Ansicht ändert sich nicht, wenn sich der UIView-Frame ändert

Ich habe eine UIView, die eine AVPlayer enthält, um ein Video anzuzeigen. Beim Ändern der Ausrichtung muss ich die Größe und den Ort des Videos ändern.

Ich bin nicht sehr erfahren mit der Größenanpassung von Ebenen, daher habe ich Probleme, die Größe des Videos zu ändern.

Ich erstelle das AVPlayer und füge seinen Player der Ebene meines videoHolderView hinzu:

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;

Zu einem späteren Zeitpunkt ändere ich die Größe und Position des Frames von videoHolderView:

[videoHolderView setFrame:CGRectMake(0, 0, 768, 502)];

An diesem Punkt brauche ich den avPlayer, um die Größe auf diese gleiche Größe zu ändern. Dies geschieht nicht automatisch - der avPlayer bleibt in der videoHolderView klein.

Wenn jemand helfen kann, würde ich mich wirklich über einen Rat freuen.

Danke Leute.

47
theDuncs

Am Ende habe ich das Problem gelöst, indem ich den AVPlayerLayer erneut zur UIView hinzugefügt habe. Ich bin nicht sicher, warum beim Ändern des Rahmens die Ebene entfernt wurde. Hier ist die endgültige Lösung:

//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];
15
theDuncs
  playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFit;
59
Markinson

Eigentlich sollten Sie die Ebene von AVPlayer nicht als Sublayer hinzufügen. Verwenden Sie stattdessen die folgende Methode in der Unterklasse der Ansicht, in der Sie AVPlayer anzeigen möchten.

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

Und verwenden Sie die folgende Zeile, um die Playerebene hinzuzufügen.

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

Ich hoffe es hilft;-)

20
Suran

Konvertierung der @ Suran-Lösung in Swift 3:

Erstellen Sie zunächst eine Klasse, die UIView erbt, wobei Sie nur 1 Variable überschreiben:

import UIKit
import AVFoundation

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

Fügen Sie dann mit dem Interface Builder eine einfache UIView hinzu und ändern Sie die Klasse in die gerade erstellte: AVPlayerView

 change class of regular UIView to AVPlayerView

Dann machen Sie einen Auslass für diese Ansicht. Nennen Sie es avPlayerView

@IBOutlet weak var avPlayerView: AVPlayerView!

Jetzt können Sie diese Ansicht innerhalb Ihres Viewcontrollers verwenden und auf dessen Avlayer wie folgt zugreifen:

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

Die Ebene folgt nun den Beschränkungen, genau wie eine normale Ebene dies tun würde. Grenzen oder Größen müssen nicht manuell geändert werden.

19
Sam

Sie können den Frame der Ebene ändern, indem Sie die -layoutSubviews-Methode überschreiben:

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

Wir haben einen großartigen Artikel von Marco Santarossa gefunden, der mehrere Ansätze für das Reparieren zeigt. https://marcosantadev.com/calayer-auto-layout-Swift/

Ich habe seinen ersten Vorschlag verwendet, um den Layer-Frame während des viewDidLayoutSubViews () -Ereignisses zurückzusetzen. 

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

die Antwort von TheDunc hat bei mir nicht funktioniert. Ich habe eine einfachere Lösung gefunden: Ich musste nur den Rahmen des AVPlayerLayer anpassen, nachdem er in der UIView geändert wurde:

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

In diesem Blog wird angegeben, dass der Rahmen einer Ansicht auch den der Ebene in ihr beeinflusst.

Wenn Sie den Rahmen einer Ansicht ändern, ändern Sie einfach den Rahmen der Ebene.

Für diesen Fall ist es nicht wahr.

2
frot.io

Um zu playerLayer zu gelangen, müssen Sie durch videoHolderView.layer.sublayers gehen und jeden ändern.

das habe ich in Swift 2.2 gemacht

if let sublayers = videoHolderView.layer.sublayers{
    for layer in sublayers where layer is AVPlayerLayer{
        layer.frame.size = ... // change size of the layer here
    }
}
1

Ich hatte dieses Problem in Swift 2.3 und konnte das Schreiben einer richtigen PlayerView-Klasse und das Festlegen als Unteransicht beheben:

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
    }

}

Im präsentierenden 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)
}
1
Giordano Scalzo

Erster Schritt: Überprüfen Sie die autoresizing-Eigenschaft von UIView in UIVIew.h

@ property (nonatomic) UIViewAutoresizing autoresizingMask; // einfache Größenänderung Der Standardwert ist UIViewAutoresizingNone

Diese Eigenschaft entspricht den Steuerelementen "Federn und Streben" in IB, obwohl Sie einige Experimente benötigen, um die gewünschten Ergebnisse zu erhalten.

1
Jay Wardell

Für diejenigen, die sich nur mit der Änderung der Größe des AVPlayer während der Gerätedrehung befassen, können Sie den Layer-Frame in der viewWillTransition-Methode (in Größe: CGSize mit Coordinator: UIViewControllerTransitionCoordinator) wie unten gezeigt ändern. 

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

Dadurch wird der Ebenenrahmen zusammen mit allen anderen Ansichten während der Drehung animiert.

0
jikigi

Jeder, der nach Xamarin-Version suchte, als ich suchte 

fügen Sie den AVPlayerLayer nicht als Sublayer hinzu, sondern setzen Sie die Ebene auf Avplayer Layer

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

Die folgende Zeile legt die Ebene fest

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