简体   繁体   English

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

[英]Fullscreen: AVPlayerLayer is not resized when resizing its parent view

I am developing a video player with the AVPlayer API from AV Foundation in MonoTouch (but a solution in objective-c could be nice too). 我正在使用MonoTouch中的AV Foundation开发AVPlayer API的视频播放器(但是Objective-c中的解决方案也可能很好)。 I am trying to implement a fullscreen mode. 我正在尝试实现全屏模式。

To display the video frames, I have a UIView (let's call it playback view) where I added the AVPlayerLayer as subview of the playback view layer: 为了显示视频帧,我有一个UIView(让我们称之为回放视图),我将AVPlayerLayer添加为回放视图层的子视图:

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

the layer properties are set like that: 图层属性设置如下:

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

to be sure that they are resized if the playback view size is changed. 确保在更改播放视图大小时调整它们的大小。 Initially, the playback view has the coordinates (0, 0, 320, 180) (only displayed at the top of the UI). 最初,回放视图具有坐标(0,0,320,180)(仅显示在UI的顶部)。 Then, I am doing a fullscreen animation by setting the playback view frame size as being the window size: 然后,我通过将回放视图框架大小设置为窗口大小来执行全屏动画:

playbackView.frame = playbackView.window.bounds;

It's works fine. 它工作正常。 The playback view is now filling all the window (set a background color to see it). 播放视图现在正在填充所有窗口(设置背景颜色以查看它)。 But my AVPlayerLayer is still staying at the top of the view like previously in non-fullscreen mode. 但我的AVPlayerLayer仍然保持在视图的顶部,就像之前在非全屏模式下一样。

Why the AVPlayer layer is not resized according to the playback view new size? 为什么AVPlayer图层不会根据播放视图的新大小调整大小? Do I need to make an animation on the AVPlayerLayer as well? 我是否还需要在AVPlayerLayer上制作动画? A refresh with setNeedsLayout, layoutSubviews (it doesn't seems to change something...)? 使用setNeedsLayout,layoutSubviews刷新(它似乎没有改变某些东西......)? Remove the AVPlayerLayer and add it again? 删除AVPlayerLayer并重新添加?

Don't add as sublayer. 不要添加为子图层。 Just use playbackView's layer as AVPlayerLayer, like this: 只需将playbackView的图层用作AVPlayerLayer,如下所示:

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

See AV Foundation Programming Guide - The Player View 请参阅AV Foundation编程指南 - 播放器视图

In case you add AVPlayerLayer as sublayer, you need to update its frame 如果您将AVPlayerLayer添加为子图层,则需要更新其框架

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

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

There is a better way to achieve this. 有一种更好的方法来实现这一目标。 Here is AVPlayerLayer -backed view, that is trying to keep video aspect ratio. 这是AVPlayerLayer -backed视图,即试图保持视频宽高比。 Just use AutoLayout as usually. 通常只使用AutoLayout。

PlayerView.h: PlayerView.h:

@interface PlayerView : UIView

@property (strong, nonatomic) AVPlayerLayer *layer;

@end

PlayerView.m: 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

And the same solution on Swift : 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
                }
            }
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM