2012-02-29 98 views
13

我正在使用MonoTouch中AV Foundation的AVPlayer API開發視頻播放器(但Objective-C中的解決方案也可能不錯)。我正在嘗試實現全屏模式。全屏:調整其父視圖時未調整AVPlayerLayer的尺寸

要顯示的視頻幀,我有一個UIView(讓我們稱之爲回放視圖)其中I添加AVPlayerLayer作爲播放視圖層的子視圖:

UIView *playbackView = ... 
AVPlayerLayer *playerLayer = ... 
[playbackView.layer addSublayer:playerLayer]; 

層屬性被設置這樣的:

playerLayer.needsDisplayOnBoundsChange = YES; 
playbackView.layer.needsDisplayOnBoundsChange = YES; 

確保在播放視圖大小發生變化時調整大小。最初,回放視圖具有座標(0,0,320,180)(僅顯示在UI的頂部)。然後,我通過將播放視圖幀大小設置爲窗口大小來製作全屏動畫:

playbackView.frame = playbackView.window.bounds; 

它工作正常。播放視圖現在正在填充所有窗口(設置背景顏色以查看它)。但是我的AVPlayerLayer仍然像以前在非全屏模式下一樣停留在視圖的頂部。

爲什麼AVPlayer圖層沒有根據回放視圖新尺寸調整大小?我是否也需要在AVPlayerLayer上製作動畫? setNeedsLayout,layoutSubviews(它似乎沒有改變什麼...)的刷新?刪除AVPlayerLayer並再次添加它?

+0

一種解決方案是也以調整根據層幀播放視圖幀(playerLayer.frame = playbackView.frame)。但是,如果我們這樣做,圖層不是動畫,而是直接顯示最終大小。我們如何能夠改變這種變化?使用核心動畫而不是UIView動畫? – nicolas 2012-03-02 07:55:33

回答

25

請勿添加爲子圖層。只要使用playbackView的層AVPlayerLayer,像這樣:

+ (Class)layerClass { 
    return [AVPlayerLayer class]; 
} 
- (AVPlayer*)player { 
    return [(AVPlayerLayer *)[self layer] player]; 
} 
- (void)setPlayer:(AVPlayer *)player { 
    [(AVPlayerLayer *)[self layer] setPlayer:player]; 
} 

AV Foundation Programming Guide - 播放器視圖

+0

如果您需要添加爲子圖層,該怎麼辦?例如,使用包含許多子圖層(包括AVPlayerLayer)的圖層託管視圖。 – Dalmazio 2015-08-21 02:28:23

+3

Apple更新了他們的AVPlayer示例,演示瞭如何使用swift實現此功能:https://developer.apple.com/library/prerelease/ios/samplecode/AVFoundationSimplePlayer-iOS/Listings/Swift_AVFoundationSimplePlayer_iOS_PlayerView_swift.html#//apple_ref/ doc/uid/TP40016103-Swift_AVFoundationSimplePlayer_iOS_PlayerView_swift -DontLinkElementID_14 – morgman 2016-03-04 19:22:25

+0

任何想法如何與NSView做到這一點?NSView沒有'layerClass' – iluvcapra 2016-08-28 21:03:27

6

如果你添加AVPlayerLayer如子,你需要更新它的框架

- (void)viewDidLayoutSubviews { 
    [super viewDidLayoutSubviews]; 

    self.avPlayerLayer.frame = self.movieContainerView.bounds; 
} 
+0

糟糕的主意。因爲是玩家,每當指示時間更新時,這個功能在調度 – jose920405 2015-08-11 15:34:35

+0

哇我的bad what壞回答!不要這樣做 – mahieddine 2015-08-26 02:15:26

+1

好的答案,對我很有幫助 – Genevios 2018-03-05 12:59:33

0

有一個更好的方法來實現這一點。這裏是AVPlayerLayer -backed視圖,即試圖保持視頻寬高比。通常使用AutoLayout。

PlayerView.h:

@interface PlayerView : UIView 

@property (strong, nonatomic) AVPlayerLayer *layer; 

@end 

PlayerView.m:

@interface PlayerView() 

@property (strong, nonatomic) NSLayoutConstraint *aspectConstraint; 

@end 

@implementation PlayerView 

@dynamic layer; 

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

- (instancetype)init { 
    self = [super init]; 
    if (self) { 
     self.userInteractionEnabled = NO; 

     [self addObserver:self forKeyPath:@"layer.videoRect" options:NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionNew context:nil]; 
    } 
    return self; 
} 

- (void)dealloc { 
    [self removeObserver:self forKeyPath:@"layer.videoRect"]; 
} 

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context { 
    if ([keyPath isEqualToString:@"layer.videoRect"]) { 
     CGSize size = [change[NSKeyValueChangeNewKey] CGRectValue].size; 
     if (change[NSKeyValueChangeNewKey] && size.width && size.height) { 
      self.aspectConstraint.active = NO; 
      self.aspectConstraint = [self.widthAnchor constraintEqualToAnchor:self.heightAnchor multiplier:size.width/size.height]; 
      self.aspectConstraint.priority = UILayoutPriorityDefaultHigh; 
      self.aspectConstraint.active = YES; 
     } 
     else { 
      self.aspectConstraint.active = NO; 
     } 
    } 
} 

@end 

而就Swift相同的解決方案:

import UIKit 
import AVFoundation 

class PlayerView : UIView { 

    override var layer: AVPlayerLayer { 
     return super.layer as! AVPlayerLayer 
    } 

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

    var aspectConstraint: NSLayoutConstraint? 

    override init(frame: CGRect) { 
     super.init(frame: frame) 
     self.isUserInteractionEnabled = false 
     self.addObserver(self, forKeyPath:"layer.videoRect", options:[.initial, .new], context:nil) 
    } 

    required init?(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder) 
     self.isUserInteractionEnabled = false 
     self.addObserver(self, forKeyPath:"layer.videoRect", options:[.initial, .new], context:nil) 
    } 

    deinit { 
     self.removeObserver(self, forKeyPath: "layer.videoRect") 
    } 

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { 
     if (keyPath == "layer.videoRect") { 
      if let rect = change?[.newKey] as? NSValue { 
       let size = rect.cgRectValue.size 
       if (size.width > 0 && size.height > 0) { 
        self.aspectConstraint?.isActive = false 
        self.aspectConstraint = self.widthAnchor.constraint(equalTo: self.heightAnchor, multiplier:size.width/size.height) 
        self.aspectConstraint?.priority = UILayoutPriorityDefaultHigh 
        self.aspectConstraint?.isActive = true 
       } 
       else { 
        self.aspectConstraint?.isActive = false 
       } 
      } 
     } 
    } 
}