2012-04-12 99 views
40

我有一個UIView,其中包含一個AVPlayer來顯示視頻。改變方向時,我需要更改視頻的大小和位置。當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中保持小尺寸。

如果有人可以幫忙,我會非常感謝任何建議。

謝謝你們。

回答

13

最後,我通過將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]; 
+0

我不確定是否需要刪除並重新添加它,但是我通過將該圖層的框架設置爲過去的持有者視圖邊界來完成此操作。 – 2015-04-13 22:50:10

+0

我將這種方式應用於我的項目,效果很好。與AVPlayerViewController和AVPlayerController相比,當您的項目仍然使用自動調整時,它具有更好的性能,並且沒有自動佈局警告問題。 – Jacky 2016-10-24 05:38:12

+0

謝謝它的作品。 – 2017-04-25 15:14:08

1

第一步:檢查出的UIView的自動尺寸財產UIVIew.h

@屬性(非原子)UIViewAutoresizing autoresizingMask; //簡單的調整大小。默認爲UIViewAutoresizingNone

此屬性記錄IB中的「彈簧和支柱」控件,但它會帶您進行一些實驗以獲得您想要的結果。

+0

Jay!謝謝!我試圖將其改變爲各種各樣的東西,但無論我設置了什麼,它都不會對視頻產生影響。在更改視圖大小以強制調整大小後,是否需要調用另一個函數? – theDuncs 2012-04-12 15:41:31

+0

你在哪裏調用[videoHolderView setNeedsLayout]? – 2012-04-12 15:53:52

+0

我不是在任何地方叫它,不。我只是在更改視圖框架後嘗試調用它,仍然沒有任何區別。 – theDuncs 2012-04-12 15:56:43

2

該Dunc的答案不適合我。我發現了一個解決方案,更簡單:我只是需要在UIView的改變之後調整AVPlayerLayer的框架:

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

this blog時所說的那樣,一個視圖的框架也影響了層在它。

當您更改視圖的框架時,它只是更改圖層的框架。

對於這種情況,這是不正確的。

+0

這是我的解決方案。現在,我在更改superLayer後設置了AVPlayerLayer。調整大小現在是好的。謝謝。 +1 – 2015-03-17 13:27:42

18

實際上,您不應該將AVPlayer的圖層添加爲子圖層。而不是你應該使用下面的方法,在你想要顯示AVPlayer的視圖的子類中。

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

並使用以下行添加(設置)播放器圖層。

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

希望它可以幫助;-)

+0

聰明!謝謝Suran。 – KPM 2015-04-16 13:01:51

+0

這工作得很好!謝謝! – 2017-01-09 21:07:55

53
playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFit; 
+0

這導致剪切視頻 – jose920405 2015-07-02 13:21:44

+4

這不解決這個問題,裁剪視頻 – 2015-11-02 19:42:23

+2

可以使用AspectFit然後代替AspectFill – NSGangster 2015-11-23 18:33:47

4

您可以通過重寫-layoutSubviews方法改變層的框架:

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

要到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 
    } 
} 
0

任何一個搜索Xamarin版本,因爲我正在尋找

不添加AVPlayerLayer如子,但設置層Avplayer層

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

下面的行設置的層

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

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

轉換@蘇冉的解決方案,以斯威夫特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() 

層將遵循制約就像一個普通的層會做。無需手動更改邊界或大小。

+0

乾淨的解決方案!作品 – 2017-02-09 20:03:37

+0

AVPlayerView僅適用於OSX。問題是關於iOS。 – 2017-04-19 13:28:29

+0

AVPlayerView是我自己定製的類;-)我不知道它是在OS X中使用的。 – Sam 2017-04-20 16:12:46

1

實測值由Marco Santarossa一個偉大的文章顯示多種方法來固定。 https://marcosantadev.com/calayer-auto-layout-swift/

我用他的第一個建議在viewDidLayoutSubViews()事件中重置了層框架。

override func viewDidLayoutSubviews() { 
    super.viewDidLayoutSubviews() 
    playerLayer.frame = view.layer.bounds 
} 
相關問題