/ swift3

Rotation support in iOS

This time I'd like to talk about the autorotation system in iOS using Swift.

First of all here is a little intro story, you can skip it if you want - by clicking here - it's my personal adventure with the Plus sized iPhone...


Is the iPhone Plus really a plus?

During the winter the battery in my iPhone 6S was dying. You must probably heard about this issue with the random turn-offs. My device had the exact same thing in cold weather conditions. Under -5°C & 49% of battery power my phone just died. It was extremely annoying, but luckily Apple announced the replacement program. So I went to the official service point, and left my phone there for almost 3 weeks. We had a spare iPhone 6S Plus in the office, so I started to using that device.

Size really matters

The Plus sized iPhone's screen is really gorgeus, but extremely useless.

I have relatively small hands, and the first thing what I noticed was that I was incapable of typing a message with one hand. Mission impossible.

Some apps looked really good in landscape mode, like the "iWorks" bundle, and one or two system apps like the maps or the notes, but what about the others?

Adaptivity is a joke.

Here comes the biggest flaw of the plus sized device. This is the landscape version of the brand new Music application:

At least the Health app tries to load in landscape mode, but...

Come on Apple, this one should be easy to adapt.

But I could continue the list: Clock, Wallet, Contacts, Watch, Activity, etc.

Almost none of the system apps are truely adaptive!

Even 3rd party apps - like Twitter - are neglecting the big screen:

Okay, enough from this madness... let's talk about the good parts.

The only good thing in the Plus sized iPhone is battery life.

Honestly? I really enjoyed watching the big screen, but because of all the dumb apps the whole plus sized device experience is horrible. Shame on you apple software engineers. Sorry, I know that you guys have a lot to do... like fixing the broken Home app since iOS10.1 meh only 50k views, but nevermind.

Now let's get back to the original topic...


Autorotation support in iOS

To build better apps for the plus sized device, you should support multiple interface orientations. With single UIViewControllers it's is a relatively easy task to do, you just have to implement a couple new methods like this.


open class ViewController: UIViewController {
#if os(iOS)
    open override var shouldAutorotate: Bool {
        return false
    }
    
    open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return .portrait
    }
    
    open override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
        return .portrait
    }
    
    open override var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
    }
#endif
}

If you have a view controller embedded inside a navigation or a tab bar controller the rotation stops working. In this case, you have to subclass the UINavigationController, and you have to return the correct values from the top view controller.
open class NavigationController: UINavigationController {
#if os(iOS)
    open override var shouldAutorotate: Bool {
        if let shouldRotate = self.topViewController?.shouldAutorotate {
            return shouldRotate
        }
        return super.shouldAutorotate
    }
    
    open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        if let orientation = self.topViewController?.supportedInterfaceOrientations {
            return orientation
        }
        return super.supportedInterfaceOrientations
    }
    
    open override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
        if let orientation = self.topViewController?.preferredInterfaceOrientationForPresentation {
            return orientation
        }
        return super.preferredInterfaceOrientationForPresentation
    }

    open override var preferredStatusBarStyle: UIStatusBarStyle {
        if let style = self.topViewController?.preferredStatusBarStyle {
            return style
        }
        return super.preferredStatusBarStyle
    }
#endif
}

The same logic applies if you have a UITabBarController, but instead of the top view controller, you have to use the selectedIndex, and return the properties based on the selected view controller.

open class TabBarController: UITabBarController {
#if os(iOS)
    open override var shouldAutorotate: Bool {
        if let viewController = self.viewControllers?[self.selectedIndex] {
            return viewController.shouldAutorotate
        }
        return super.shouldAutorotate
    }
    
    open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        if let viewController = self.viewControllers?[self.selectedIndex] {
            return viewController.supportedInterfaceOrientations
        }
        return super.supportedInterfaceOrientations
    }
    
    open override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
        if let viewController = self.viewControllers?[self.selectedIndex] {
            return viewController.preferredInterfaceOrientationForPresentation
        }
        return super.preferredInterfaceOrientationForPresentation
    }

    open override var preferredStatusBarStyle: UIStatusBarStyle {
        if let viewController = self.viewControllers?[self.selectedIndex] {
            return viewController.preferredStatusBarStyle
        }
        return super.preferredStatusBarStyle
    }
#endif
}

One more thing: why don't we have a protocol for this?
protocol ViewControllerAutorotationSupport {
    var shouldAutorotate: Bool { get }
    var supportedInterfaceOrientations: UIInterfaceOrientationMask { get }
    var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation { get }
    var preferredStatusBarStyle: UIStatusBarStyle { get } 
}

I really hope that Apple will refactor UIKit & AppKit and this year they might introduce the unified AppleKit designed especially for Swift. C'mon guys drop the legacy tech! ;) // just kidding