ビデオを表示する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内の小さなサイズのままです。
誰かが助けてくれるなら、どんなアドバイスでも本当に感謝しています。
みんなありがとう。
最後に、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];
playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFit;
@SuranのソリューションをSwiftに変換する:
最初に、1つの変数のみをオーバーライドするUIViewを継承するクラスを作成します。
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()
これで、レイヤーは通常のレイヤーと同じように制約に従います。境界またはサイズを手動で変更する必要はありません。
実際には、AVPlayerのレイヤーをサブレイヤーとして追加しないでください。その代わりに、AVPlayerを表示するビューのサブクラスで、次のメソッドを使用する必要があります。
+ (Class)layerClass
{
return [AVPlayerLayer class];
}
次の行を使用して、プレーヤーレイヤーを追加(設定)します。
[(AVPlayerLayer *)self.layer setPlayer:self.avPlayer];
それが役に立てば幸い;-)
-layoutSubviews
メソッドをオーバーライドすることにより、レイヤーのフレームを変更できます。
- (void)layoutSubviews
{
[super layoutSubviews];
self.playerLayer.frame = self.bounds;
}
Marco Santarossaによる、修正への複数のアプローチを示す素晴らしい記事を見つけました。 https://marcosantadev.com/calayer-auto-layout-Swift/
彼の最初の提案を使用して、viewDidLayoutSubViews()イベント中にレイヤーフレームをリセットしました。
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
playerLayer.frame = view.layer.bounds
}
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)
}
theDuncの答えはうまくいきませんでした。より簡単なソリューションを見つけました:UIViewで変更した後、AVPlayerLayerのフレームを調整する必要がありました。
avPlayerLayer.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
このブログ には、ビューのフレームもその中のレイヤーのフレームに影響することが記載されています。
ビューのフレームを変更する場合、レイヤーのフレームを変更するだけです。
この場合、それは真実ではありません。
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
}
}
最初のステップ:UIVIew.hでUIViewの自動サイズ変更プロパティを確認します
@property(nonatomic)UIViewAutoresizing autoresizingMask; //単純なサイズ変更。デフォルトはUIViewAutoresizingNoneです
このプロパティは、IBの「スプリングとストラット」コントロールに対応しますが、必要な結果を得るためにいくつかの実験が必要になります。
デバイスの回転中にAVPlayerのサイズ変更のみに関心がある場合は、以下に示すように、viewWillTransition(size:CGSize、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)
}
これにより、回転中にレイヤーフレームと他のすべてのビューがアニメーション化されます。
私が探していたXamarinバージョンを探している人
aVPlayerLayerをサブレイヤーとして追加しないで、レイヤーをAvplayerレイヤーに設定します
[Export("layerClass")]
public static Class LayerClass()
{
return new Class(typeof(AVPlayerLayer));
}
次の行はレイヤーを設定します
(this.Layer as AVPlayerLayer).Player = _player; // Acplayer