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
.
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
Swift: Protocol VS. Struct VS. Class
Exc_Bad_Access Using Ibinspectable
How to Make a Popup Window with an Image Swift
How to Completely Reload a View So That Viewdidload Gets Run Again
Errortype' Is Not Convertible to 'Nserror'
When Should I Use Anyobject Insted of Uibutton in Swift
Cannot Invoke Initializer for Type Unsafemutablepointer<Uint8>
Getting Uiwebview API Deprecation Message After Adding Paypal Pod in My iOS App
Most Efficient/Realtime Way to Get Pixel Values from iOS Camera Feed in Swift
Multiple Iboutlets in Same Line of Same Type in Swift
Finding It Difficult to Pass Data to Separate Viewcontroller
Core Data Taking Time to Insert Records with Fetching Entity & Set as Relationship
How to Use Searchbar for API'S
Reload View When @Published Is Changed