7

I'm trying to set the size/frame of the video I'm showing in my view, using AutoLayout. But I can't figure out how to do it properly. This is the code for my view:

import UIKit
import AVKit

class VideoMeetingView: UIView {

    lazy var playerLayer: AVPlayerLayer = {
        let layer = AVPlayerLayer()
        return layer
    }()

    private lazy var videoView: UIView = {
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        view.backgroundColor = .blue
        return view
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.backgroundColor = #colorLiteral(red: 0.5725490451, green: 0, blue: 0.2313725501, alpha: 1)
        self.addSubviewsAndConstraints()

        playerLayer.frame = videoView.bounds
        videoView.layer.addSublayer(playerLayer)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    private func addSubviewsAndConstraints() {
        self.addSubview(videoView)

        videoView.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
        videoView.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
        videoView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
        videoView.heightAnchor.constraint(equalToConstant: 600).isActive = true
    }

}

If I print out the values of videoView.bounds it's just (0, 0, 0, 0), so I guess AutoLayout does not update value as I first thought.

If I set the size of playerLayer.frame manually using CGRect everything works as it should. But I want to use AutoLayout.

So how can I set AvPlayerLayer's size using AutoLayout?

eivindml
  • 2,197
  • 7
  • 36
  • 68

1 Answers1

19

Do:

self.playerLayer = {
   let layer = AVPlayerLayer(player: self.player)
    layer.videoGravity = .resizeAspect
    layer.needsDisplayOnBoundsChange = true
    return layer
}()

which causes the layer to resize aspect fit when the bounds of its parent changes.

Also, you MIGHT have to add:

override func layoutSubviews() {
    super.layoutSubviews()

    self.playerLayer.frame = self.bounds
}

so that it has the right frame no matter what..

Another option is to make the AVPlayerLayer the actual layer of the UIView itself instead of a sub-layer:

class VideoView : UIView
{
    override var layer: CALayer {
        return AVPlayerLayer.class
    }
}
Brandon
  • 22,723
  • 11
  • 93
  • 186
  • Thank you. It worked. I had to add the `layoutSubviews()` function as well. And set it to `self.videoView.bounds`. Why does it work when set in `layoutSubviews()` function, but not in the `init()` method? Why is videoView's `bounds` still `(0.0, 0.0, 0.0, 0.0)` at this point? – eivindml Jan 05 '18 at 17:12
  • 3
    @eivindml; When you create a view, it isn't laid out yet until it is added to another view or viewController and ready to be displayed. For this reason, unless you explicitly set a frame, then the frame by default will be `.zero`. When using auto-layout, it will call `layoutSubviews` to finalize update to the view's children. At this point, your view has laid out and you can use its bounds. Note: DO NOT use its frame because frame can be modified by animations and transformations and would give you the wrong info :D Glad it worked. – Brandon Jan 05 '18 at 19:21