Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rotation only in one ViewController

I am trying to rotate one view while all other views (5) are fixed to portrait. The reason is that in that one view I want the user to watch pictures which he saved before. I guess this is possible but so far I couldn't figure out how to achieve that. Can anyone help or give me a hint? I am programming that in Swift running on iOS8

like image 481
Armin Scheithauer Avatar asked Jan 30 '15 19:01

Armin Scheithauer


People also ask

How do I force landscape in Swift?

Setting the app upWhen on the main screen, under the orientation section, you will see a number of options like 'Auto-rotate OFF', 'Auto-rotate ON', 'Forced Portrait' and 'Forced Landscape'. As the names suggest, you can use these buttons as one-tap shortcuts to toggle the orientation of your device.

How do I change the orientation in react native?

For Android, open the AndroidManifest. xml file and within the activity element add 'android:screenOrientation="portrait"' to lock to portrait or 'android:screenOrientation="landscape"' to lock to landscape.

Which setting in an IOS device do you need to enable if you want to test the application for various orientation modes?

From ios 10.0 we need set { self. orientations = newValue } for setting up the orientation, Make sure landscape property is enabled in your project.


4 Answers

I'd recommend using supportedInterfaceOrientationsForWindow in your appDelegate to allow rotation only in that specific view controller, ex:

Swift 4/Swift 5

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {

    // Make sure the root controller has been set
    // (won't initially be set when the app is launched)
    if let navigationController = self.window?.rootViewController as? UINavigationController {

        // If the visible view controller is the
        // view controller you'd like to rotate, allow
        // that window to support all orientations
        if navigationController.visibleViewController is SpecificViewController {
            return UIInterfaceOrientationMask.all
        } 

        // Else only allow the window to support portrait orientation
        else {
            return UIInterfaceOrientationMask.portrait
        }
    }

    // If the root view controller hasn't been set yet, just
    // return anything
    return UIInterfaceOrientationMask.portrait
}

Note that if that SpecificViewController is in landscape before going to a portrait screen, the other view will still open in landscape. To circumvent this, I'd recommend disallowing transitions while that view is in landscape.


Swift 3

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int {

    // Make sure the root controller has been set
    // (won't initially be set when the app is launched)
    if let navigationController = self.window?.rootViewController as? UINavigationController {

        // If the visible view controller is the
        // view controller you'd like to rotate, allow
        // that window to support all orientations
        if navigationController.visibleViewController is SpecificViewController  {
            return Int(UIInterfaceOrientationMask.All.rawValue)
        }

        // Else only allow the window to support portrait orientation
        else {
            return Int(UIInterfaceOrientationMask.Portrait.rawValue)
        }
    }

    // If the root view controller hasn't been set yet, just
    // return anything
    return Int(UIInterfaceOrientationMask.Portrait.rawValue)
}
like image 51
Lyndsey Scott Avatar answered Nov 15 '22 23:11

Lyndsey Scott


You can also do it in a protocol oriented way. Just create the protocol

protocol CanRotate {

}

Add the the same 2 methods in the AppDelegate in a more "swifty" way

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    if topViewController(in: window?.rootViewController) is CanRotate {
        return .allButUpsideDown
    } else {
        return .portrait
    }
}


func topViewController(in rootViewController: UIViewController?) -> UIViewController? {
    guard let rootViewController = rootViewController else {
        return nil
    }

    if let tabBarController = rootViewController as? UITabBarController {
        return topViewController(in: tabBarController.selectedViewController)
    } else if let navigationController = rootViewController as? UINavigationController {
        return topViewController(in: navigationController.visibleViewController)
    } else if let presentedViewController = rootViewController.presentedViewController {
        return topViewController(in: presentedViewController)
    }
    return rootViewController
}

And in every ViewController that you want a different behaviour, just add the protocol name in the definition of the class.

class ViewController: UIViewController, CanRotate {}

If you want any particular combination, they you can add to the protocol a variable to override

protocol CanRotate {
    var supportedInterfaceOrientations: UIInterfaceOrientationMask
}
like image 34
Cristian Pena Avatar answered Nov 16 '22 00:11

Cristian Pena


Sometimes when you're using a custom navigation flow (that may get really complex) the above-mentioned solutions may not always work. Besides, if you have several ViewControllers that need support for multiple orientations it may get quite tedious.

Here's a rather quick solution I found. Define a class OrientationManager and use it to update supported orientations in AppDelegate:

class OrientationManager {
    static var landscapeSupported: Bool = false
}

Then in AppDelegate put the orientations you want for that specific case:

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
        if OrientationManager.landscapeSupported {
            return .allButUpsideDown
        }
        return .portrait
    }

Then in the ViewControllers that you want to have multiple navigations update the OrientationManager:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    OrientationManager.landscapeSupported = true
}

Also, don't forget to update it once again when you'll be exiting this ViewController:

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    OrientationManager.landscapeSupported = false
    //The code below will automatically rotate your device's orientation when you exit this ViewController
    let orientationValue = UIInterfaceOrientation.portrait.rawValue
    UIDevice.current.setValue(orientationValue, forKey: "orientation")
}

Hope this helps!

Update:

You may just want to add a static func to your Orientation Support Manager class:

    static func setOrientation(_ orientation: UIInterfaceOrientation) {
        let orientationValue = orientation.rawValue
        UIDevice.current.setValue(orientationValue, forKey: "orientation")
        landscapeSupported = orientation.isLandscape
    }

Then you can call this function whenever you need to set the orientation back to portrait. That will also update the static landscapeSupported value:

OSM.setOrientation(.portrait)
like image 27
Nikita Alexander Avatar answered Nov 16 '22 00:11

Nikita Alexander


This is for Swift 4 and Swift 5. You can use the follow code in your AppDelegate.swift :

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    guard let rootViewController = self.topViewControllerWithRootViewController(rootViewController: window?.rootViewController),
     (rootViewController.responds(to: Selector(("canRotate")))) else {
        // Only allow portrait (standard behaviour)
        return .portrait;
    }
    // Unlock landscape view orientations for this view controller
    return .allButUpsideDown;
}

private func topViewControllerWithRootViewController(rootViewController: UIViewController!) -> UIViewController? {
    guard rootViewController != nil else { return nil }
    
    guard !(rootViewController.isKind(of: (UITabBarController).self)) else{
        return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UITabBarController).selectedViewController)
    }
    guard !(rootViewController.isKind(of:(UINavigationController).self)) else{
        return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UINavigationController).visibleViewController)
    }
    guard !(rootViewController.presentedViewController != nil) else {
        return topViewControllerWithRootViewController(rootViewController: rootViewController.presentedViewController)
    }
    return rootViewController
}

You can then make a custom UIViewController rotate by overriding shouldAutorotate

like image 42
gandhi Mena Avatar answered Nov 16 '22 01:11

gandhi Mena