Search code examples
objective-cuiviewcalayeravplayer

AVPlayer layer inside a view does not resize when UIView frame changes


I have a UIView which contains an AVPlayer to show a video. When changing orientation, I need to change the size and location of the video.

I'm not very experienced with resizing layers, so I'm having problems making the video resize.

I start by creating the AVPlayer and adding its player to my videoHolderView's layer:

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;

Then, at a later point, I change the size and location of the videoHolderView's frame:

[videoHolderView setFrame:CGRectMake(0, 0, 768, 502)];

At this point, I need the avPlayer to resize to these same dimension. This doesn't happen automatically - the avPlayer stays at it's small size within the videoHolderView.

If anyone can help, I'd really appreciate any advice.

Thanks guys.


Solution

  • Converting @Suran's solution to Swift:

    First, create a class inheriting UIView where you override only 1 variable:

    import UIKit
    import AVFoundation
    
    class AVPlayerView: UIView {
        override class var layerClass: AnyClass {
            return AVPlayerLayer.self
        }
    }
    

    Then add a simple UIView using the interface builder and change its class to the one you just created: AVPlayerView

    change class of regular UIView to AVPlayerView

    Then, make an outlet for that view. Call it avPlayerView

    @IBOutlet weak var avPlayerView: AVPlayerView!
    

    Now, you can use that view inside your viewcontroller and access its avlayer like this:

    let avPlayer = AVPlayer(url: video)
    let castLayer = avPlayerView.layer as! AVPlayerLayer
    castLayer.player = avPlayer
    avPlayer.play()
    

    The layer will now follow the constraints just like a regular layer would do. No need to manually change bounds or sizes.