首页 文章

全屏:调整其父视图大小时不调整AVPlayerLayer的大小

提问于
浏览
14

我正在使用MonoTouch中的AV Foundation开发AVPlayer API的视频播放器(但是Objective-c中的解决方案也可能很好) . 我正在尝试实现全屏模式 .

为了显示视频帧,我有一个UIView(让我们称之为回放视图),我将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并重新添加?

3 回答

  • 6

    不要添加为子图层 . 只需将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添加为子图层,则需要更新其框架

    - (void)viewDidLayoutSubviews {
        [super viewDidLayoutSubviews];
    
        self.avPlayerLayer.frame = self.movieContainerView.bounds;
    }
    
  • 26

    有一种更好的方法来实现这一目标 . 这是 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
                    }
                }
            }
        }
    }
    

相关问题