Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS ViewController doesn't layout properly after orientation change

I'm writing an iOS application with some fixed (portrait) views and some orientation dependent views (portrait, lanscape left and landscape right).

The views are contained in a Custom Navigation Controller based on the following code:

class CustomNavigationViewController: UINavigationController {
    override func supportedInterfaceOrientations() -> Int {
        return self.topViewController.supportedInterfaceOrientations()
    }

    override func shouldAutorotate() -> Bool {
        return self.topViewController.shouldAutorotate()
    }
}

I'm implementing supportedInterfaceOrientations() and shouldAutorotate() inside nav child controllers.

Here is a Test Controller

class TestViewController: UIViewController {
    var shouldRotate: Bool = false

    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        self.shouldRotate = true
    }

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    convenience init(rotation shouldRotate: Bool) {
        self.init(nibName: "TestViewController", bundle: nil)
        self.shouldRotate = shouldRotate
    }

    override func supportedInterfaceOrientations() -> Int {
        if shouldRotate == false {
            return UIInterfaceOrientation.Portrait.rawValue
        } else {
            return super.supportedInterfaceOrientations()
        }
    }

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

    override func didRotateFromInterfaceOrientation(fromInterfaceOrientation: UIInterfaceOrientation) {
        println("from: \(fromInterfaceOrientation.rawValue)")
    }

    @IBAction func buttonTapped(sender: AnyObject) {
        let newvc = TestViewController(rotation: true)
        self.navigationController?.pushViewController(newvc, animated: true)
    }
}

The first controller is instantiated inside the AppDelegate with rotation: false. The other controllers are created with rotation: true and pushed after tapping the button.

Here is a screenshot of the view:

first controller

If I change orientation on the controllers after the first one (the rotable ones) I get the following result:

rotated controller

The controller xib uses autolayout and if I rotate the device before tapping the button it works as expected with the view filling the whole screen.

Also, if I tap the back button while the phone is in landscape the first view is locked in this state:

enter image description here

I'm deploying the app to iOS 8.

How can I make the first view portrait only and the other views correctly layed out after a rotation?

like image 370
Luca Avatar asked Oct 30 '22 19:10

Luca


1 Answers

It's probably doesn't matter since it's only printing out a debug message, but don't forget that didRotateFromInterfaceOrientation(_:) was depreciated in iOS 8 with viewWillTransitionToSize(_:withTransitionCoordinator:) taking it's place for responsibilities of a change in view size (which includes rotation).

I think you're on the right track, but instead of overriding both shouldAutorotate() and supportedInterfaceOrientations() only override supportedInterfaceOrientations().

I just did a quick POC to see if it would work. I'm not setting a flag when creating the view controller (and using Swift 2) but you get the idea:

class RotatingViewController: UIViewController {
    override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
        return UIInterfaceOrientationMask.All
    }
}

class FixedViewController: UIViewController {
    override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
        return UIInterfaceOrientationMask.Portrait
    }
}

class NavigationController: UINavigationController {
    override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
        return self.topViewController?.supportedInterfaceOrientations() ?? UIInterfaceOrientationMask.All
    }
}

I think what's happening in your demo is that when you're transitioning to a view controller that is fixed, you're asking it to go into a portrait orientation (which it is) but then not allowing the screen to rotate back to portrait mode.

So.. just try deleting your 'shouldAutorotate()' in your CustomNavigationViewController and see if that works.

like image 91
MathewS Avatar answered Nov 15 '22 00:11

MathewS