How to handle device rotation since iOS 8

Back in the iOS 5 days, there was a method called shouldAutorotateToInterfaceOrientation. Since iOS 8 we’re no longer meant to use that, and instead use a much better technique: size classes.

In a nutshell, iOS 8 and above will call the viewWillTransitionToSize method on your UIViews. This looks a bit more complex than it actually is, because it contains two optional blocks:

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator {
    // code here will be executed before rotation

This method allows us to execute code before or after the transition from portrait to landscape, or vice versa. But there’s also a method from the transition coordinator that we can intercept so we can execute code during the transition (the actual rotation). Here’s what it looks like in context:

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator {
    // best call super just in case
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
    // will execute before rotation
    [coordinator animateAlongsideTransition:^(id  _Nonnull context) {
        // will execute during rotation
    } completion:^(id  _Nonnull context) {
        // will execute after rotation

I also snuck in the super call, just in case a custom view has any code in their parent method. Optional, but I thought I’d mention it for good practice.

Example: rotating an image view

Let’s assume we’re setting up an image view manually in viewDidLoad. By default it won’t rotate with the rest of the interface:

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // add an image to the current view
    UIImage *image = [UIImage imageNamed:@"miami-coke"];
    UIImageView *imageView = [[UIImageView alloc]initWithFrame:self.view.bounds];
    imageView.image = image;
    imageView.contentMode = UIViewContentModeScaleAspectFit;
    imageView.tag = 87;
    [self.view addSubview:imageView];

To make that view look handsome on rotation, we need to change its bounds and centre properties when the animation happens. It looks less handsome when we do it after the interface rotates, so we’ll implement the coordinator’s animateAlongsideTransition block I’ve shown you above:

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator {
    // before rotation
    [coordinator animateAlongsideTransition:^(id  _Nonnull context) {
        // during rotation: update our image view's bounds and centre
        UIImageView *imageView = [self.view viewWithTag:87];
        imageView.bounds = self.view.bounds; =;
    } completion:^(id  _Nonnull context) {
        // after rotation

I don’t have a property to my image view in this case, so I’m grabbing a reference using viewWithTag.

How to detect if we’re in portrait or landscape mode?

Anywhere in the above method we can make use of the size property: size.width and size.height will show us the interface orientation in points (for example, 320 for iPhones in portrait mode, and 567 in landscape mode).

3 thoughts on “How to handle device rotation since iOS 8

  1. Is there a way to PREVENT a subview (that you added manually in viewDidLoad) from rotating? I understand that the shouldAutorotate method on the root view controller will be consulted to figure out if the whole root view controller should rotate or not, but a view from another view controller will be at the mercy of the root view controller.

    I have searched stack overflow far and wide for a solution for this — many have asked the question, but none have answered it.

    If this cannot be done, how do you rotate a view/navigation bar/popover manually in iOS 8+? Perhaps if I return NO for shouldAutorotate in the root view controller (and thus prevent the subview from rotating), I can then listen for orientation notifications and manually rotate the pieces that I want to rotate.

    Thanks for your help.

Leave a Reply