-2

Question: How do I dismiss B, Present C, and Not Show A?

So there are three view controllers (A, B, and C). View A presents view B. Tapping a button on B should dismiss B and show C. The transition should appear to be direct from B -> C.

Option 1 - Fail

It can't be a simple segue presenting C because I need B to go away.

Option 2 - Fail

This thread almost answers my question. It suggests using delegation to call a function in A, which dismisses B and presents C. I tried it and it certainly dismisses B and presents C, but even with animation turned off it clearly shows B-> A -> C. The user sees A, so it's no good.

Option 3 - Fail

I also tried using an unwind segue. However, it just unwinds to A and stops. It appears that the presentSegue in A's unwind function fails to present C because it runs too early.

Note:

I'm not using a navigation controller, in case that matters

Community
  • 1
  • 1
Dave G
  • 10,974
  • 7
  • 49
  • 74
  • Do you have to dismiss B when going to C? What if when you're done with C you returned from C to A and B was dismissed then without being seen. Would that be good enough? – vacawama Jan 05 '16 at 02:22
  • @vacawama It depends, you have to imagine there's also a D. My fear is creating a mess where then the user can click to D, then to A, and keep going without any ever being dismissed. I figure it's cleaner to always dismiss and go directly from A -> ___. Not sure if that makes sense. – Dave G Jan 05 '16 at 02:41

2 Answers2

0

This will only work when B is wrapped in a navigation controller.

  • A presents(modal) navcontroller-wrapped-B.
  • B pushes C
  • Immediately after pushing(in the next line) set the viewControllers property to and array of just C.

Something like:

self.navigationController!.pushViewController(C, animated: true)
self.navigationController.viewControllers = [C]

Hope this helps.

Max
  • 2,941
  • 1
  • 29
  • 30
0

You might want to reconsider your navigation pattern, as it is not something you can easily do. There's a navigation controller for that purpose, so why not to use it?

If you still want to do it your way, I can only think of adding a screenshot of dismissed view controller while presenting a new one. I'll give an example in Objective C, convert it to Swift yourself if needed.

Add UIViewController+Replace.h file to your project:

#import <UIKit/UIKit.h>

@interface UIViewController (Replace)

- (void)replaceWithViewController:(UIViewController* __nonnull)viewController animated:(BOOL)animated completion:(void (^ __nullable)(void))completion;

@end

Also add UIViewController+Replace.m:

#import "UIViewController+Replace.h"

static UIImage* RenderImageFromView(UIView *view, CGRect frame)
{
    UIGraphicsBeginImageContextWithOptions(frame.size, YES, 0);
    CGContextRef context = UIGraphicsGetCurrentContext();
    [view.layer renderInContext:context];
    UIImage *renderedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return renderedImage;
}

@implementation UIViewController (Replace)

- (void)replaceWithViewController:(UIViewController *)viewController animated:(BOOL)animated completion:(void (^)(void))completion
{
    UIViewController *parentController = [self presentingViewController];
    NSAssert(parentController != nil, @"Cannot replace root view controller");

    CGRect bounds = self.view.frame;

    UIImageView *captureView = [[UIImageView alloc] initWithFrame:bounds];
    captureView.image = RenderImageFromView(self.view, bounds);
    [parentController.view addSubview:captureView];

    [self dismissViewControllerAnimated:NO completion:^{
        [parentController presentViewController:viewController animated:animated completion:^{
            [captureView removeFromSuperview];
            if (completion)
                completion();
        }];
    }];
}

@end

Then do #import "UIViewController+Replace.h" in B and open view controller C from it's code:

UIViewController *c = [self.storyboard instantiateViewControllerWithIdentifier:@"ViewControllerC"]; 
// or instantiate it whatever way you want

[self replaceWithViewController:c animated:YES completion:nil]

But again, it is some weird way of doing navigation. After all, modal view controllers are not intended for navigation.

Alex Skalozub
  • 2,341
  • 12
  • 13