AVPlayer force landscape mode for fullscreen

King David picture King David · May 16, 2016 · Viewed 7.7k times · Source

I am playing a video using an AVPlayer which is about 320x200 frame in my app. The avplayer also has a custom 'fullscreen' button added as overlay, like the youtube app player. How can I implement it such that when the app is in portrait mode and the user clicks fullscreen button, the video will rotate to fullscreen but in landscape mode? I tried using transform and it works partially, because when its in fullscreen mode, if user switches device to portrait orientation; the avplayer frame changes abruptly. I want it to work like the youtube app i.e. when in fullscreen mode, it should stay so even if user rotates device. Only should return to original size when turn off fullscreen. I don't want to use avplayerviewcontroller due to design of the app. Thanks in advance for help.

Answer

Eric Armstrong picture Eric Armstrong · Apr 17, 2017

Great question! Allowing the AVPLayerLayer to go fullscreen is important. A considerable amount of app configuration for a single view to handle both portrait and landscape, just to display a full screen video? Please.

Transforms and frame manipulation can solve this issue:

extension CGAffineTransform {

    static let ninetyDegreeRotation = CGAffineTransform(rotationAngle: CGFloat(M_PI / 2))
}

extension AVPlayerLayer {

    var fullScreenAnimationDuration: TimeInterval {
        return 0.15
    }

    func minimizeToFrame(_ frame: CGRect) {
        UIView.animate(withDuration: fullScreenAnimationDuration) {
            self.setAffineTransform(.identity)
            self.frame = frame
        }
    }

    func goFullscreen() {
        UIView.animate(withDuration: fullScreenAnimationDuration) {
            self.setAffineTransform(.ninetyDegreeRotation)
            self.frame = UIScreen.main.bounds
        }
    }
}

Setting the frame of the AVPlayerLayer changes it's parent's frame. Save the original frame in your view subclass, to minimize the AVPLayerLayer back to where it was. This allows for autolayout.

IMPORTANT - This only works if the player is in the center of your view subclass.

Incomplete example:

class AVPlayerView: UIView {

    fileprivate var avPlayerLayer: AVPlayerLayer {
        return layer as! AVPlayerLayer
    }

    fileprivate var hasGoneFullScreen = false
    fileprivate var isPlaying = false
    fileprivate var originalFrame = CGRect.zero

    func togglePlayback() {
        if !hasGoneFullScreen {
            originalFrame = frame
            hasGoneFullScreen = true
        }

        isPlaying = !isPlaying
        if isPlaying {
            avPlayerLayer.goFullscreen()
            avPlayerLayer.player?.play()
        } else {
            avPlayerLayer.player?.pause()
            avPlayerLayer.minimizeToFrame(originalFrame)
        }
    }
}