142

I'm trying to implement the new viewWillTransitionToSize method which has been introduced in iOS 8 (all other rotation methods have been deprecated). I'd like to know what the equivalent of didRotateFromInterfaceOrientation is now as there are a number of clean up tasks we need to perform and I can't see a block that we can assign to UIViewControllerTransitionCoordinator in order to be called when 'transition' to a new size finishes. Thanks.

strange
  • 9,654
  • 6
  • 33
  • 47

7 Answers7

263

Okay found it, just have to use the animateAlongsideTransition:completion: method on the passed UIViewControllerTransitionCoordinator.

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{   
    [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context)
    {
        UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
        // do whatever
    } completion:^(id<UIViewControllerTransitionCoordinatorContext> context)
    { 

    }];

    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
}
Can
  • 8,502
  • 48
  • 57
strange
  • 9,654
  • 6
  • 33
  • 47
  • Will this method call every time we rotate like didRotateFromInterfaceOrientation?. Can you please share me the method you have used. Thank you – ask123 Jun 23 '14 at 07:44
  • 2
    Yes it will. This is what I do: `- (void) viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator { [coordinator animateAlongsideTransition:^(id context) { UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation]; // do whatever } completion:^(id context) { }]; [super viewWillTransitionToSize: size withTransitionCoordinator: coordinator]; }` – strange Jun 26 '14 at 18:39
  • @strange: Thats great. It would be nice if you could add the code snippet in the answer itself. It looks congested in the comment – Rashmi Ranjan mallick Oct 13 '14 at 05:41
  • @strange: I have another problem in iOS 8. I have a universal iOS application. This should support all the orientations in iPads and only portrait (home button down) in iPhones. But we need one particular view controller to be locked in landscape mode only in both iPads and iPhones. And once you navigate out of that view controller, it should again support the old orientations. How to achieve this? Please help. – Rashmi Ranjan mallick Oct 13 '14 at 05:49
  • 1
    Thanks - i'll add a swift version as an answer to save people some time – DogCoffee Mar 10 '15 at 08:11
  • Is there a way to remove the animation? – Jessica May 12 '15 at 05:17
  • it will call when you press power button and minimize the app. – Rajneesh071 May 16 '16 at 11:21
  • Holy hell, Apple make it hard, don't they? If it wasn't for Stack Overflow contributors such as yourself, I doubt anyone would make anything of substantial worth with the iOS APIs. It's an absolute mess at this point. – Womble May 17 '16 at 03:11
  • even having this "[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; " at the bottom makes difference – Umit Kaya Aug 18 '16 at 09:53
  • 3
    statusbarorientation is deprecated in iOS 9. What else is the option? – Deepak Sharma Apr 13 '17 at 11:25
  • 1
    @DeepakSharma I'm a little late to the party, but you can use `[UIDevice currentDevice].orientation`. You can also pipe this into `UIDeviceOrientationIsPortrait([UIDevice currentDevice].orientation)` or `UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation)`. Hope this helps! – Jeff Nov 17 '17 at 04:21
72

The Swift Version of the answer by strange

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {

    coordinator.animateAlongsideTransition({ (UIViewControllerTransitionCoordinatorContext) -> Void in

        let orient = UIApplication.sharedApplication().statusBarOrientation

        switch orient {
        case .Portrait:
            println("Portrait")
            // Do something
        default:
            println("Anything But Portrait")
            // Do something else
        }

        }, completion: { (UIViewControllerTransitionCoordinatorContext) -> Void in
            println("rotation completed")
    })

    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
}
DogCoffee
  • 19,820
  • 10
  • 87
  • 120
  • It's strange because I put this in my ViewController, and it didn't `print` anything to my log. I guess because this method is not being called. Can you think of anything else that would need to be plugged in order for this to work? – Trip Mar 10 '16 at 08:46
  • I just added it to a empty project (Universal App) and it works fine without the need to add anything. Maybe put a log statement at the very beginning of the method and see if its being called. I cannot think of anything that you would need to add. What iOS you running? – DogCoffee Mar 10 '16 at 09:11
  • @DogCoffee..its not getting called. Has it anything to do with Simulator? – Saty Jun 18 '16 at 05:21
  • @Saty works in simulator as well - just checked again then. Works as expected. – DogCoffee Jun 18 '16 at 06:51
  • is there a way to do this without subclassing UIVIewController, because we are doing MVVM-C – Andrius Steponavičius Sep 19 '16 at 10:23
  • 1
    statusbarorientation is deprecated in iOS 9. What else is the option? – Deepak Sharma Apr 13 '17 at 11:28
10

iOS 10.3 & Swift 3

override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) {

        coordinator.animate(alongsideTransition: { (_) in
            let orient = newCollection.verticalSizeClass

            switch orient {
            case .compact:
                print("Lanscape")///Excluding iPads!!!

            default:
                print("Portrait")
            }
        }, completion: { _ in
            print("rotation completed")
        })

        super.willTransition(to: newCollection, with: coordinator)
    }
Mike Glukhov
  • 1,758
  • 19
  • 18
7

The accepted answer in Swift 3:

override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) {
    coordinator.animate(alongsideTransition: { (_) in
        let orient = UIApplication.shared.statusBarOrientation

        switch orient {
        case .portrait:
            print("Portrait")
        // Do something
        default:
            print("Anything But Portrait")
            // Do something else
        }
    }, completion: { (UIViewControllerTransitionCoordinatorContext) -> Void in
      print("rotation completed")
    })

    super.willTransition(to: newCollection, with: coordinator)
}

It works fine for me

j_gonfer
  • 1,547
  • 21
  • 21
  • Doesn't work for me on iOS 10 — it prints the old orientation, not the new one. – Kartick Vaddadi Mar 12 '17 at 02:57
  • 1
    @VaddadiKartick because you should use `let orient = newCollection.verticalSizeClass switch orient { case .compact: print("Lanscape") // Do something default: print("Portrait") // Do something else }` – Mike Glukhov Apr 11 '17 at 11:58
5

Since the question was: what was the equivalent of didRotateFromInterfaceOrientation

I thought I'd contribute the code below:

@implementation ViewController
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
    [super traitCollectionDidChange:previousTraitCollection];
    if (previousTraitCollection.verticalSizeClass == UIUserInterfaceSizeClassRegular) {
        NSLog(@"User has rotated to landscape");
    } else if (previousTraitCollection.verticalSizeClass == UIUserInterfaceSizeClassCompact) {
        NSLog(@"User has rotated to portrait");
    }
}
@end

I was testing on an iPhone in the simulator, but my print statements won't get run if I test using the iPad since the traitsCollection won't change.

This is strange because this is exactly what Apple recommends:

- (void) traitCollectionDidChange: (UITraitCollection *) previousTraitCollection {
    [super traitCollectionDidChange: previousTraitCollection];
    if ((self.traitCollection.verticalSizeClass != previousTraitCollection.verticalSizeClass)
        || self.traitCollection.horizontalSizeClass != previousTraitCollection.horizontalSizeClass)) {
        // your custom implementation here
    }
}
Tunaki
  • 132,869
  • 46
  • 340
  • 423
NYC Tech Engineer
  • 1,845
  • 2
  • 22
  • 23
3

[[UIApplication sharedApplication] statusBarOrientation] is deprecated in iOS9 you have to test against UITraitCollection for various devices.

  override func willTransitionToTraitCollection(newCollection: UITraitCollection, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {

    if newCollection.containsTraitsInCollection(UITraitCollection(verticalSizeClass: .Regular)) {
      ...
    }
  }
Yannick
  • 535
  • 4
  • 18
  • 6
    Only the setter was deprecated. An Apple employee posted, "Reading the status bar orientation is not deprecated, only writing to it is. This may have been an error in how we constructed the header if you are seeing this on the getter." (https://forums.developer.apple.com/thread/12937) – Graham Perks Oct 20 '15 at 15:37
  • Isn't the getter also deprecated though. According to the [documentation](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplication_Class/index.html#//apple_ref/occ/instp/UIApplication/statusBarOrientation) it is. – Groot Jan 05 '16 at 09:11
1

On the Ipad there is no trait collection change so here is how you detect the rotation from start and completion. Here is the Swift 5 syntax:

override func viewWillTransition(to size: CGSize, with coordinator: 
UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)

    coordinator.animate(alongsideTransition: { [unowned self] _ in

        self.view.backgroundColor = UIColor.blue
        print("rotation in progress")

    }) { [unowned self] _ in
        self.view.backgroundColor = UIColor.green
        print("rotation complete")


    }
}
Avi Pogrow
  • 11
  • 3