King David
King David

Reputation: 139

AVPlayer force landscape mode for fullscreen

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.

Upvotes: 4

Views: 9935

Answers (2)

Eric Armstrong
Eric Armstrong

Reputation: 666

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)
        }
    }
}

Upvotes: 9

HSG
HSG

Reputation: 1224

In my opinion, you should create a FullScreenViewController, which is forced always supporting landscape. Then present that view controller from your current one when press "fullscreen" button and also pass AVPlayer instance to it, then set frame for AVPlayerLayer and resume playing. After dismissing, it would be back to normal, I mean your "portrait" mode.

Upvotes: 4

Related Questions