2012-02-29 40 views
13

Tôi đang phát triển trình phát video với API AVPlayer từ AV Foundation trong MonoTouch (nhưng giải pháp trong mục tiêu-c cũng có thể tốt đẹp). Tôi đang cố gắng triển khai chế độ toàn màn hình.Toàn màn hình: AVPlayerLayer không được thay đổi kích thước khi thay đổi kích thước chế độ xem gốc

Để hiển thị các khung hình video, tôi có một UIView (chúng ta hãy gọi nó xem phát lại), nơi tôi đã thêm các AVPlayerLayer như subview của lớp xem phát lại:

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

các thuộc tính lớp được thiết lập như thế:

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

để đảm bảo rằng chúng được thay đổi kích thước nếu kích thước chế độ xem phát lại bị thay đổi. Ban đầu, chế độ xem phát lại có tọa độ (0, 0, 320, 180) (chỉ hiển thị ở đầu giao diện người dùng). Sau đó, tôi đang thực hiện hoạt ảnh toàn màn hình bằng cách đặt kích thước khung xem phát lại dưới dạng kích thước cửa sổ:

playbackView.frame = playbackView.window.bounds; 

Nó hoạt động tốt. Chế độ xem phát lại hiện đang lấp đầy tất cả cửa sổ (đặt màu nền để xem). Nhưng AVPlayerLayer của tôi vẫn đang ở trên đầu của chế độ xem như trước đây ở chế độ không toàn màn hình.

Tại sao lớp AVPlayer không bị thay đổi kích thước theo chế độ xem phát lại kích thước mới? Tôi có cần tạo hoạt ảnh trên AVPlayerLayer không? Làm mới với setNeedsLayout, layoutSubviews (nó dường như không thay đổi gì đó ...)? Hủy bỏ AVPlayerLayer và thêm nó một lần nữa?

+0

Một giải pháp là thay đổi kích thước cũng là khung lớp theo khung xem phát lại trong khi hoạt ảnh (playerLayer.frame = playbackView.frame). Nhưng nếu chúng ta làm điều đó, lớp không phải là hoạt hình nhưng được hiển thị trực tiếp với kích thước cuối cùng. Làm thế nào chúng ta có thể sinh động cũng thay đổi này? Sử dụng Core Animation thay vì hoạt ảnh UIView? – nicolas

Trả lời

25

Không thêm làm lớp con. Chỉ cần sử dụng lớp playbackView như AVPlayerLayer, như thế này:

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

Xem AV Foundation Programming Guide - The Player Xem

+0

Nếu bạn cần thêm làm lớp con thì sao? Ví dụ: sử dụng chế độ xem được lưu trữ trên lớp có chứa nhiều lớp con, bao gồm cả trình AVPlayerLayer. – Dalmazio

+3

Apple đã cập nhật ví dụ AVPlayer của họ bằng phiên bản thể hiện cách triển khai điều này bằng cách sử dụng nhanh: 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

+0

Bất kỳ ý tưởng làm thế nào để làm điều này với một NSView?NSView không có 'layerClass' – iluvcapra

6

Trong trường hợp bạn thêm AVPlayerLayer như lớp con, bạn cần cập nhật khung của nó

- (void)viewDidLayoutSubviews { 
    [super viewDidLayoutSubviews]; 

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

ý tưởng tồi. Bởi vì là một cầu thủ, mỗi khi thời gian chỉ báo được cập nhật chức năng này trong công văn – jose920405

+0

wow những gì một câu trả lời xấu tôi đang bị nghẹt thở! đừng làm điều này – mahieddine

+1

Câu trả lời hay, vì tôi đã giúp rất nhiều – Genevios

0

Có một cách tốt hơn để đạt được điều này. Dưới đây là AVPlayerLayer chế độ xem ngược, đang cố gắng giữ tỷ lệ co của video. Chỉ cần sử dụng AutoLayout như thường lệ.

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 

Và cùng một giải pháp trên 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 
       } 
      } 
     } 
    } 
} 
Các vấn đề liên quan