Avplayer Not Full Screen in Landscape Mode Using iOS Swift

AVPlayer not full screen in landscape mode using iOS swift

After spending some time taking a good look at the Storyboard, I tried changing the fill to Aspect fill & fit and that resolved the problem :)

AVPlayer force landscape mode for fullscreen

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

AVPlayerViewController full screen rotation behavior in portrait only app

When you leave player full screen you enter in viewWillApper of your View Controller. So in viewWillAppear try to set your window frame to be equal to your screen bounds.

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
appDelegate.window?.rootViewController?.view.frame = UIScreen.main.bounds
}

AVPlayer exitFullScreen

SwiftUI seems get lost connection with representable in this scenario... anyway it is better UIKit things to be handled within UIKit flow. Representable concept has Coordinator for such cases.

So a possible approach to fix is to move everything inside AVPlayerControllerRepresentable.

Sample Image

Here is main part (tested with Xcode 13.4 / iOS 15.5):

    func makeUIViewController(context: UIViewControllerRepresentableContext<AVPlayerControllerRepresentable>) -> AVPlayerViewController {
let controller = AVPlayerViewController()
controller.player = player
controller.showsPlaybackControls = false;

context.coordinator.playerController = controller
return controller
}

class Coordinator: NSObject, AVPlayerViewControllerDelegate {
weak var playerController: AVPlayerViewController? {
didSet {
playerController?.delegate = self
}
}

private var subscriber: AnyCancellable? = nil
override init() {
super.init()
subscriber = NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)
.sink { [weak self] _ in
self?.rotated()
}
}

func rotated() {
if UIDevice.current.orientation.isLandscape {
self.enterFullScreen(animated: true)
} else {
self.exitFullScreen(animated: true)
}
}

//...

Test module on GitHub

swift 3 - play video in fullscreen when rotated to landscape

O.k. so i managed to play the video fullscreen by adding the video to an AVPlayerLayer and setting it's size to the view when Device is landscape.

override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) {

if (UIDevice.current.orientation.isLandscape) {

DispatchQueue.main.async {
self.view.didAddSubview(self.controllsContainerView)
self.layer = AVPlayerLayer(player: self.player!)
self.layer?.frame = self.view.frame
self.layer?.videoGravity = AVLayerVideoGravityResizeAspectFill
self.view.layer.addSublayer(self.layer!)

}
print("Device is landscape")
}

when UIDevice.cuurent.orientation.islandscape == false i remove subLayer and set the view back to videoContainer bounds.

else{
print("Device is portrait")
movie.view.frame = videoContainerView.bounds
controllsContainerView.frame = videoContainerView.bounds
self.layer?.removeFromSuperlayer()

}

hope it helps anyone.

iOS 8 - change orientation back to portrait when dismissing full screen AVPlayerViewController

Rather than implementing application(_:supportedInterfaceOrientationsForWindow:) try implementing supportedInterfaceOrientations() on each view controller. So for example:

override func supportedInterfaceOrientations() -> Int {
return Int(UIInterfaceOrientationMask.Portrait.rawValue)
}

This will ensure that the view controller cannot be displayed in landscape, so when dismissing the video player, it will come straight back to a portrait window.

Update Objective-C:

- (NSUInteger)supportedInterfaceOrientations { 
return UIInterfaceOrientationMaskPortrait;
}

iOS: AVPlayerViewController enable fullscreen rotation in portrait oriented application

Swift 2.2
In AppDelegate to allow rotation for player:

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
guard let vc = (window?.rootViewController?.presentedViewController) else {
return .Portrait
}

if (vc.isKindOfClass(NSClassFromString("AVFullScreenViewController")!)) {
return .AllButUpsideDown
}

return .Portrait
}

Than create and use subclass of AVPlayerViewController for back to portrait mode when player exit full screen mode:

class YourVideoPlayer: AVPlayerViewController {

override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if view.bounds == contentOverlayView?.bounds {
UIDevice.currentDevice().setValue(UIInterfaceOrientation.Portrait.rawValue, forKey: "orientation")
}
}


Related Topics



Leave a reply



Submit