简体   繁体   中英

Present new view controller and invisibly dismiss the current chain of presented view controllers

So I have a chain of view controllers (usually 2 - 3) where the first one is the root view controller and the next are presented with presentViewController:animated: .

That is an onboarding part of the application and when user finally gets to the part where I would need to show the main UI, I'd like to dismiss all the onboarding view controllers (except for the root view controller) before showing the main UI view controller which is a UITabBarController . The reason why I want to do that is - I don't need them anymore and I wouldn't like keeping those view controller in memory.

Now the problem is - I would like this to look like I'm just presenting UITabBarController, I don't want the user to see the dismiss of the previous viewcontrollers.

First thing that I tried:

  1. Call dismissViewControllerAnimated:completion: on the root view controller with animated: NO
  2. On completion do presentViewController:animated:completion: with animated: YES to show my UITabBarController

Sadly that flashed root view controller before showing the animation of presenting my UITabBarController.

Sophisticated solution that I tried:

  1. Take a snapshot of the main window
  2. Add the snapshot as the subview of the root view controller's view
  3. Call dismissViewControllerAnimated:completion: on the root view controller with animated: NO
  4. On completion do presentViewController:animated:completion: with animated: YES to show my UITabBarController
  5. On completion of presentViewController: remove the snapshot view from the root view controller's view

Here is the code that does that. It is a bit more complex because it also handles popping the root view controller's child view controllers since the root view controller is UINavigationController:

- (void)popNavToRootAndPresentViewController:(UIViewController *)viewController
{
    UINavigationController *rootVC = (UINavigationController *)self.view.window.rootViewController;

    // if we have a chain of presented view controllers over our nav vc, then we need to dismiss them
    if (rootVC.presentedViewController) {
        // we need a snapshot view because even if dismissing without animation, root view controller will flash for a fraction of a second.
        __block UIView *snapShotView = [self.view.window snapshotViewAfterScreenUpdates:NO];

        [rootVC.view addSubview:snapShotView];

        // hide the currently presented view controller chain without animation. This won't be visible since we've added the snapshot on the rootVC
        [rootVC dismissViewControllerAnimated:NO completion:^{

            // present the new view controller that we need
            [rootVC presentViewController:viewController animated:YES completion:^{
                // pop to root in case there are more than one pushed to nav stack
                [rootVC popToRootViewControllerAnimated:NO];
                // we don't need the snapshot view anymore
                [snapShotView removeFromSuperview];
            }];

        }];
    } else {
        [rootVC presentViewController:viewController animated:YES completion:^{
            // we presented our vc from the nav vc, so we can pop the nav vs itself to root - that won't be noticable
            [rootVC popToRootViewControllerAnimated:NO];
        }];
    }

}

Even with inserting the snapshot of the current view hierarchy, I still have a flash. With this solution dismissViewControllerAnimated results in a short flash of the view controller that is the previous one in the chain (the one that presented self).

Is there a way that desired result can be achieved without flicker? I guess that something like that could be achieved with custom parent view controller and child viewcontrollers, since then there is more control on how views are replaced, but I'd really like to keep it simple and use presentViewController: .

You could simply present (animated) the tab bar controller on top of all the other controllers, once the animation is done, you can dismiss all the controllers back to the root and present the tab bar controller again, this time not animated.

Make sure you keep a reference to the tab bar controller so you don't have to re-allocate a new version.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM