75

I have downloaded a simpleCamera view from Cocoa Controls which use this method

- (AVCaptureVideoOrientation)orientationForConnection
{
    AVCaptureVideoOrientation videoOrientation = AVCaptureVideoOrientationPortrait;
    switch (self.interfaceOrientation) {
        case UIInterfaceOrientationLandscapeLeft:
            videoOrientation = AVCaptureVideoOrientationLandscapeLeft;
            break;
        case UIInterfaceOrientationLandscapeRight:
            videoOrientation = AVCaptureVideoOrientationLandscapeRight;
            break;
        case UIInterfaceOrientationPortraitUpsideDown:
            videoOrientation = AVCaptureVideoOrientationPortraitUpsideDown;
            break;
        default:
            videoOrientation = AVCaptureVideoOrientationPortrait;
            break;
    }
    return videoOrientation;
}

the problem is "interfaceOrientation" deprecated in iOS 8 but i dont know what and how to replace this in Switch condition.

GetMe4GetMe
  • 927
  • 1
  • 7
  • 12

5 Answers5

147

Getting the device orientation is not correct. For instance, the device might be in landscape mode, but a view controller that only supports portrait will remain in portrait.

Instead, use this:

[[UIApplication sharedApplication] statusBarOrientation]

Another bonus is that it still uses the UIInterfaceOrientation enum, so very little of your code needs to change.

cetcet
  • 2,147
  • 2
  • 15
  • 15
  • 13
    `statusBarOrientation` deprecated in iOS 9 - https://developer.apple.com/documentation/uikit/uiapplication/1623026-statusbarorientation?language=objc – Pang Jul 06 '17 at 08:24
21

Since iOS8, Apple recommends to use TraitCollections (Size Classes) instead of interfaceOrientation.

Moreover, since iOS 9 and the new iPad feature "Multitasking", there are some cases where the device orientation doesn't fit with the window proportions! (breaking your application UI)

So you should also be very careful when using Regular Size Classes because it will not necessary take up the whole iPad screen.

Sometimes TraitCollections doesn't fill all your design needs. For those cases, Apple recommends to compare view's bounds :

if view.bounds.size.width > view.bounds.size.height {
    // ...
}

I was quite surprised, but you can check on the WWDC 2015 video Getting Started with Multitasking on iPad in iOS 9 at 21'15.

Maybe you're really looking for the device orientation and not for the screen or window proportions. If you care about the device camera, you should not use TraitCollection, neither view bounds.

Patrick Pijnappel
  • 7,317
  • 3
  • 39
  • 39
vmeyer
  • 1,998
  • 21
  • 23
  • Indeed its mentioned . Thanks!! – Ankish Jain Jul 13 '16 at 11:38
  • Is there a recommended way to know if device is landscape left or right? It really matters with iPhone X's notch :( – Pavel Alexeev Dec 25 '17 at 21:05
  • Well, you can use `[[UIDevice currentDevice] orientation]` if you'd like to check real device orientation, but you should not use it for iPhone X adaptation. Please use new iOS 11 safe area or old layout margin. – vmeyer Jan 02 '18 at 08:15
3

Swift 4+ version

UIApplication.shared.statusBarOrientation
Abhishek Jain
  • 4,557
  • 2
  • 32
  • 31
  • 2
    In iOS 13, this method gives "'statusBarOrientation' is deprecated: first deprecated in iOS 13.0 - Use the interfaceOrientation property of the window scene instead." message – Peter Johnson Jul 24 '19 at 16:06
2

Using -orientation property of UIDevice is not correct (even if it could work in most of cases) and could lead to some bugs, for instance UIDeviceOrientation consider also the orientation of the device if it is face up or down, there is no pair in UIInterfaceOrientation enum for those values.
Furthermore, if you lock your app in some particular orientation, UIDevice will give you the device orientation without taking that into account.
On the other side iOS8 has deprecated the interfaceOrientation property on UIViewController class.
There are 2 options available to detect the interface orientation:

  • Use the status bar orientation
  • Use size classes, on iPhone if they are not overridden they could give you a way to understand the current interface orientation

What is still missing is a way to understand the direction of a change of interface orientation, that is very important during animations.
In the session of WWDC 2014 "View controller advancement in iOS8" the speaker provides a solution to that problem too, using the method that replaces -will/DidRotateToInterfaceOrientation.

Here the proposed solution partially implemented:

-(void) viewWillTransitionToSize:(CGSize)s withTransitionCoordinator:(UIVCTC)t {
    orientation = [self orientationFromTransform: [t targetTransform]]; 
    oldOrientation = [[UIApplication sharedApplication] statusBarOrientation]; 
    [self myWillRotateToInterfaceOrientation:orientation duration: duration]; 
    [t animateAlongsideTransition:^(id <UIVCTCContext>) {
         [self myWillAnimateRotationToInterfaceOrientation:orientation
                                                  duration:duration];
      }
      completion: ^(id <UIVCTCContext>) {
         [self myDidAnimateFromInterfaceOrientation:oldOrientation];
      }];
}
Andrea
  • 26,120
  • 10
  • 85
  • 131
0

When you use UIApplication.shared.statusBarOrientation, Xcode 11 will show the warning 'statusBarOrientation' was deprecated in iOS 13.0: Use the interfaceOrientation property of the window scene instead.

This answer is in Swift 5, and supports both iOS 13 and lower versions. It assumes the following:

  • You will create only one scene, and never more than one
  • You wish to contain your code to a specific view
  • You have a view that has a member variable previewLayer of type AVCaptureVideoPreviewLayer

First, in your SceneDelegate.swift, add the following lines:

    static var lastCreatedScene: UIWindowScene?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        guard let newScene = (scene as? UIWindowScene) else { return }
        Self.lastCreatedScene = newScene
    }

Then in your view, add the following function and call it in layoutSubviews():

    func refreshOrientation() {
        let videoOrientation: AVCaptureVideoOrientation
        let statusBarOrientation: UIInterfaceOrientation
        if #available(iOS 13, *) {
            statusBarOrientation = SceneDelegate.lastCreatedScene?.interfaceOrientation ?? .portrait
        } else {
            statusBarOrientation = UIApplication.shared.statusBarOrientation
        }
        switch statusBarOrientation {
        case .unknown:
            videoOrientation = .portrait
        case .portrait:
            videoOrientation = .portrait
        case .portraitUpsideDown:
            videoOrientation = .portraitUpsideDown
        case .landscapeLeft:
            videoOrientation = .landscapeLeft
        case .landscapeRight:
            videoOrientation = .landscapeRight
        @unknown default:
            videoOrientation = .portrait
        }
        self.previewLayer.connection?.videoOrientation = videoOrientation
    }
Bart van Kuik
  • 4,704
  • 1
  • 33
  • 57