1

I have a UITabBarController as my rootViewController and based on an action, I call presentViewController on the tabBarController which works fine. The controller that is presented is a UINavigationController

Based on an action in that I want to transition from the currently presented UINavigationController to a different UINavigationController by using transitionFromViewController:toViewController:duration:options:animations:completion: but throws an error:

Parent view controller is using legacy containment in call to -[UIViewController transitionFromViewController:toViewController:duration:options:animations:completion:]

People talk about getting this when calling it on UINavigationController but this is for a UITabBarController which I hope is different.

Ultimately I'd like to transition from the currently presented UINavigationController to a new UINavigationController with a cross dissolve. I can dismiss the first one and present the second one but its slides from the bottom. Is this possible?

Rudiger
  • 6,749
  • 13
  • 51
  • 102

1 Answers1

1

A technique that always works for me, when transitions don't work the way you want, is to simply use some smoke and mirrors. This is a generally-great technique to understand and have in your tool belt.

Here is my recipe:

A)You take a screenshot of you current screen: (borrowed from How Do I Take a Screen Shot of a UIView?)

UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
CGRect rect = [keyWindow bounds];
UIGraphicsBeginImageContextWithOptions(rect.size,YES,0.0f);
CGContextRef context = UIGraphicsGetCurrentContext();
[keyWindow.layer renderInContext:context];   
UIImage *capturedScreen = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

B) Create a UIImageView with your screenshot and add it to your new viewController

UIImageView *fakeScreen = [UIImageView alloc] initWithImage:captureScreen];
 //accessing .view isn't best practice, consider using a dedicated property inside your UIViewController subclass, here just for the sake of explanation
[secondViewController.view addSubview:fakeScreen];

C) Dimisss the current view controller, making sure to not animate it, in your case the UINavigationController [navigationController dismissViewControllerAnimated:NO completion:nil];

D) Present your new view controller, don't animate it either. (secondViewController) and then, fade out the imageView.

[self.tabBarController presentViewController:secondViewController animated:NO completion:NO];
    [UIView animateWithDuration:0.08 animations:^{
        fakeScreen.alpha = 0;
    } completion:
         ^{[
       fakeScreen removeFromSuperview]; ];

This give you a normal fade. If you wanted to do a real crossfade, you will need to get a bit creative with your second viewController's content: you'll need a root view with two children: a contentview (for the content that is fading in) and the fakeView (which will be fading out).

Community
  • 1
  • 1
Arie Litovsky
  • 4,893
  • 2
  • 35
  • 40
  • Not a terrible answer but I'd like to avoid this if possible. – Rudiger Sep 09 '13 at 06:47
  • What is the error you are getting which you describe in your question? – Arie Litovsky Sep 09 '13 at 07:02
  • added to original question – Rudiger Sep 09 '13 at 07:13
  • 1
    It's not possible to do what you want given the method you have. If you check the docs and .h files, there are 2 red flags: "Finally, the receiver should not be a subclass of an iOS container view controller." as well as "This method is only intended to be called by an implementation of a custom container view controller". You are not using custom containment here. My solution is an alternative which, although you may not like, is actually used often by Apple to optimize complex animations. – Arie Litovsky Sep 10 '13 at 21:56