34

Since willAnimateRotationToInterfaceOrientation:duration: is deprecated in iOS8, one needs to use viewWillTransitionToSize:withTransitionCoordinator: instead.

However, this method does not get called in my view controller on iOS8. Is there anything else, I need to implement, in order for this callback to work?

I cannot find anything in the documentation. The only thing I could find, was that it belongs to the new UIContentContainer protocol. However, even if I am adding this to the protocols of my controller explicitly, it does not work.

Any ideas?

tschubotz
  • 343
  • 1
  • 3
  • 6
  • I was loading my viewController as a view for segmented buttons. In such case I was not getting viewWillTransitionToSize:withTransitionCoordinator: called. How are you trying to load the viewController? – Surendra Oct 07 '14 at 22:10

3 Answers3

42

The viewWillTransitionToSize:withTransitionCoordinator: seems to only work if the interface is actually going to change size, meaning we have rotated 90 degrees. If you have a mask on your layout that only allows landscape, when rotation 180 degrees, the interface size doesn't change, so this method doesn't seem to be called.

I have worked around this in my app by instead registering to the UIDeviceOrientationDidChangeNotification notification like:

(In my view controller's viewWillAppear):

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChange:) name:UIDeviceOrientationDidChangeNotification object:nil];
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];

(An in my viewWillDisappear [remember to unsubscribe])

[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];

My deviceOrientationDidChange: looks like:

- (void)deviceOrientationDidChange:(NSNotification *)notification {
    UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
    [self willRotateToInterfaceOrientation:orientation duration:1.0];
}
Mustafa
  • 20,504
  • 42
  • 146
  • 209
line72
  • 436
  • 5
  • 3
  • this workaround also worked for me and seems the best explanation so far – tschubotz Oct 09 '14 at 19:52
  • 1
    For those of you with no status bar looking to do a non-standard rotation this works well too: `- (void)deviceOrientationDidChange:(NSNotification *)notification { UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation]; NSLog(@"rotation %li", (long)orientation); }` – Ford Davis Sep 12 '16 at 07:30
  • this is the best answer, it worked! – Muneeb Rehman Aug 08 '23 at 10:53
36

As per the docs, remember to call super

- (void)viewWillTransitionToSize:(CGSize)size
       withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];

    // ...
}

Otherwise child view controllers will not get the message forwarded on to them.

Robert
  • 37,670
  • 37
  • 171
  • 213
  • While this is a useful suggestion I am perhaps missing how this is answering the original question...? – yura Jul 16 '15 at 15:34
  • Thank you, In my case: I miss call add childViewController. :D – Linh Nguyen Aug 16 '15 at 07:27
  • @yura if another class is receiving the message and not passing it on with a call to super, the class you're working in might not receive it. – arlomedia Oct 16 '15 at 22:30
7

I know this question is a bit old at this point but I think the issue might be solved a different way for some who may come across it. If you are trying to load a view that is part of a DIFFERENT controller by using addSubview(controller.view), you need to also add that controller to the parent as well (possibly the view you are adding to's controller). If you do not add the controller to a parent you will never receive the updates for size changes. We later found out the reason for Apple's API change; with the iPad pro, your SizeClass can change without rotation with the multi-tasking ability. This will also call the method:

viewWillTransitionToSize(size: CGSize, 
        withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)

In the parent class, if you override the above method, make sure you call super as well or you will just find another way to beat your head against a wall...

Sepui
  • 611
  • 6
  • 12
  • Awesome... fixed my problem. I was NOT calling super, and this method wasn't being called. Started calling super, and pow... started working. – Logicsaurus Rex Jun 02 '16 at 16:35
  • +1 for :- If you are trying to load a view that is part of a DIFFERENT controller by using addSubview(controller.view), you need to also add that controller to the parent as well (possibly the view you are adding to's controller). If you do not add the controller to a parent you will never receive the updates for size changes. – paran Aug 14 '17 at 10:53
  • Thanks a lot for this!. I didn't notice that in my parent view (for most of my app) I didn't call super on it, hence none of the child views where executing these methods. – Edward B Sep 26 '17 at 23:59