49

I have an UIViewController, I want to disable or enable rotation of the screen in different scenarios

Example:

if flag {
   rotateDevice = false
}
else {
   rotateDevice = true
}

How can I do that?

iOS
  • 5,450
  • 5
  • 23
  • 25
Bao Tuan Diep
  • 2,221
  • 2
  • 17
  • 23

8 Answers8

81

I have the answer. On AppDelegate, if you rotate device, push viewcontroller, etc. This function always call

Update for swift 3/4

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask
{
    return self.restrictRotation
}

self.restrictRotation is a custom parameter.

How to use:

In Appdelegate:

 var restrictRotation:UIInterfaceOrientationMask = .portrait

In ViewController:

When method ViewDidLoad or viewWillAppear is called. We will change like this:

(UIApplication.shared.delegate as! AppDelegate).restrictRotation = .all 

and then this method on AppDelegate will be called.

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask
Bao Tuan Diep
  • 2,221
  • 2
  • 17
  • 23
  • 2
    what is `self.restrictRotation` here? Where it is decleared? –  May 06 '17 at 06:27
  • @NileshPol that is parameter you have to create. before rotate device or change UIViewController, that function will be called. – Bao Tuan Diep Sep 12 '17 at 03:12
  • @NileshPol you will have to create that parameter with datatype UIInterfaceOrientationMask – Harshad Madaye Apr 16 '19 at 12:21
  • 2
    I followed this method, but there's a problem. If you're in landscape on a `.all` view controller, and then you go to a new viewcontroller (with the correct code as above in `viewWillAppear` set to permit `.portrait` only), that new view controller stays in landscape. I'll keep hunting for a fix. – legoblocks Sep 07 '20 at 05:41
  • Gracias! Worked like a charm. – VoidMain Jan 28 '21 at 00:47
36

You simply have to implement shouldAutorotate and supportedInterfaceOrientations into your UIViewController. Take a look at this documentation. For example:

override func shouldAutorotate() -> Bool {
    return true
}

You can also specify which orientations are available. Here is an example with only portraits orientations:

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    return .Landscape
}

Edit: If you want to support different orientation regarding a flag, you just have to do something like this:

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    if myFlag {
        return .Landscape
    } else {
        return .All
    }
}

(If myFlag is true, it will allow Landscape orientation. Otherwise, it will allow all orientations).

Dave
  • 479
  • 3
  • 13
Julien Quere
  • 2,407
  • 16
  • 21
22

swift 4

override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    get {
        return .portrait

    }
}
Baryon Lee
  • 1,157
  • 11
  • 11
  • 6
    Adding an expanation would make the answer clear. not only for the OP, but future users experiencing this problem as well. – Gerhard Sep 07 '18 at 12:09
  • This is method from UIViewController, overriding it will prevent from rotating screen – Jakub C Jan 03 '19 at 01:31
19

In swift 5, as from previous, if you want to allow (avoid others) a particular UIViewController to rotate in a certain orientation you have to override "supportedInterfaceOrientations" inside your UIViewController class like so:

class MyViewController:UIViewController {
    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return .portrait
    }
}

Here there are the possible options:

public struct UIInterfaceOrientationMask : OptionSet {

    public init(rawValue: UInt)

    
    public static var portrait: UIInterfaceOrientationMask { get }

    public static var landscapeLeft: UIInterfaceOrientationMask { get }

    public static var landscapeRight: UIInterfaceOrientationMask { get }

    public static var portraitUpsideDown: UIInterfaceOrientationMask { get }

    public static var landscape: UIInterfaceOrientationMask { get }

    public static var all: UIInterfaceOrientationMask { get }

    public static var allButUpsideDown: UIInterfaceOrientationMask { get }
}

Extended

If you want to be able to distinguish between iPad or iPhone you could use UIUserInterfaceIdiom:

override var supportedInterfaceOrientations: UIInterfaceOrientationMask{
    get{
        return UIDevice.current.userInterfaceIdiom == .phone ? [.portrait, . portraitUpsideDown]:.all //OBS -> You can also return an array
    }
}

where:

public enum UIUserInterfaceIdiom : Int {

    
    case unspecified

    @available(iOS 3.2, *)
    case phone // iPhone and iPod touch style UI

    @available(iOS 3.2, *)
    case pad // iPad style UI

    @available(iOS 9.0, *)
    case tv // Apple TV style UI

    @available(iOS 9.0, *)
    case carPlay // CarPlay style UI
}
Elijah
  • 8,381
  • 2
  • 55
  • 49
Reimond Hill
  • 4,278
  • 40
  • 52
  • 1
    You can also check for the device type inside `get`. Let's say iPhones should only be allowed to use portrait orientation with this ViewController but iPads (and whatever else there is) can use every orientation: `if UIDevice.current.userInterfaceIdiom == .phone { return .portrait } else { return .all }`. – Neph Jul 09 '19 at 14:15
  • @Neph Ok, in this case you can also see another answer I wrote some time ago https://stackoverflow.com/a/53006873/1824565 – Reimond Hill Jul 09 '19 at 14:20
  • I was more talking about the orientation, not the size "type". ;) – Neph Jul 10 '19 at 10:26
  • @Neph I see what you mean. you can use UIUserInterfaceIdiom see my answer – Reimond Hill Jul 10 '19 at 10:39
  • I am, look at my comment. ;) No need to over complicate it like in your first edit though. – Neph Jul 10 '19 at 11:08
  • There is no need to write get and you can even omit the return: override var supportedInterfaceOrientations: UIInterfaceOrientationMask { .portrait } – LightMan Nov 29 '19 at 12:38
  • An important thing to mention: This won't work in the `UIViewController` class if it's affected by a segue/`UINavigationController` (it's never called). You have to use the code in the `UINavigationController`'s class instead. I'm not sure how to do that with a regular "show" segue though. – Neph Apr 12 '21 at 12:41
  • Correct, if it's embedded in a UINavigationController you need to put this code in there. Try setting shouldAutorotate to true. Then present modally the navigation – Reimond Hill Apr 12 '21 at 14:03
  • You can simply write without `get {}` in your `override` – Vitalik Kizlov Nov 22 '21 at 13:53
10

An easy solution for the most common request (iPhone: portrait, iPad: all) in your AppDelegate:

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    return UIDevice.current.userInterfaceIdiom == .phone ? .portrait : .all
}
Display Name
  • 4,502
  • 2
  • 47
  • 63
  • 1
    This is actually a great approach in many cases: it applies to the whole app and actually allows to keep things different depending on the device. Exactly what I was looking for. – cdf1982 Dec 06 '21 at 16:07
0

Found this to be by far the simplest implementation, and adaptable to use on specific view controllers. Add this to viewController class, after viewDidLoad()

override open var shouldAutorotate: Bool {
        return false
    }
Mr_P
  • 523
  • 2
  • 16
0

swift 5

override var shouldAutorotate: Bool {
    false
}
hectorsvill
  • 681
  • 8
  • 7
-5

set device orientarion portrait in Target -> General -> Deployment Info -> Portrait

enter image description here

NGR
  • 1,230
  • 2
  • 15
  • 44
  • this is the right answer. What happened to being able to override autorotate in the view controller? it used to be a function, now it's a var and when I try and override it has no effect - haven't been able to find a satisfying answer yet – nbpeth Dec 27 '17 at 01:35
  • 29
    Downvote: This is a **wrong** answer, the title is `disable rotate on one UIViewController` not for the whole app. – Tancrede Chazallet Apr 06 '18 at 07:39
  • 1
    Downvote, but not below zero - it's the right answer to a different question, not a misleading answer. – AmitaiB Dec 14 '18 at 17:01
  • I personally feel like if the question were worded "iOS. How to enable and disable rotation on each AND EVERY UIViewController?" ... this would be an appropriate answer as each and every can easily translate into ALL view controllers.... it disables the rotate for the entire application... I found this overall thread because I wanted to disable rotate for my entire app, and it worked for me so thats why I chose to give this an upvote.. This entire response may not have been mentioned if the question were more specific. no hard feelings anywhere... Thanks for the help everyone! – Evan Howington Jan 01 '19 at 19:51
  • That will affect all UIViewControllers – Reimond Hill Jun 12 '19 at 13:29