Coordinator Pattern (c. 23): How to animate between sibling routes

I’m using the coordinator pattern as detailed in chapter 23 to manage the flow of my app, starting with an App Coordinator that manages two routes respectively – Onboarding and Home. At the end of the Onboarding route I need to switch to the Home route which the App Coordinator can do easily. However how do I go about animating the transition between these when I am popping the Onboarding route which has been displayed modally on top of the root controller and then subsequently modally presenting the Home route?

@jrg.developer Can you please help with this when you get a chance? Thank you - much appreciated! :]

Thanks for the question, @alekplay :]

Remember that design patterns are a starting point, not a concrete implementation. Thereby, there are several ways you could go about doing this! Ultimately, the one you pick depends largely on how you intend/expect this code to grow over time.

As one possibility, you could have 3 coordinators:

  • A parent coordinator that owns two coordinators.
  • A child coordinator for the onboarding route.
  • A child coordinator for the home route.

Whenever you reach the end of the onboarding flow, you can have the onboarding child coordinator delegate back to the parent coordinator and dismiss.

In response to the delegate callback, the parent coordinator could inform the home child coordinator to start.

I like this architecture because it’s easy to grow horizontally: If/when you need new flows, you can create a new coordinator for them!

Of course, each coordinator would also have a router that it actually uses to start/end the flow and to present/dismiss intermediary controllers as appropriate.

You can have the parent coordinator instantiate these routers as well, or if you’re using an injection framework (e.g. Swinject), you can have it do the actual instantiation of everything.

I hope this helps!

Best of luck,

Joshua

Thanks for your reply @jrg.developer!

I currently have a AppCoordinator which holds a splash screen and logic to determine which child coordinator to display, it then instantiates either two of the HomeCoordinator or OnboardingCoordinator which are displayed modally using a custom transition.

When the OnboardingCoordinator dismisses itself, the callback on AppCoordinator will instantiate and display the HomeCoordinator.

The problem I run into is handling the transition between the Onboarding Coordinator’s displayed view controller and the new Home Coordinator’s view controller, without revealing the App Coordinator’s splash view controller in-between.

I could dismiss the old VC, wait a second, and then present the new VC but that’s not very pretty – do you have any recommendations here?

@jrg.developer Do you have any feedback about this? Thank you - much appreciated! :]

Why not present the new HomeCoordinator and then dismiss the OnboardingCoordinator, without animation? At the very least, you could “hide” the dismissing of the OnboardingCoordinator, right?

Yowever, you will need to reconsider how your dimiss(animated:) method works for your Router. E.g., the simple implementation given in this chapter looks like this:

public func dismiss(animated: Bool) {
  performOnDismissed(for:
    navigationController.viewControllers.first!)
  parentViewController.dismiss(animated: animated,
                               completion: nil)
}

If you choose to “dismiss” after “present,” this implementation wouldn’t work for you, because it assumes that the view controller that’s first (navigationController.viewControllers.first!) is the one that you want to “dismiss.”

Instead, you might consider holding onto whatever view controller is the “first” for a new type of Router, and use it to “dismiss.” Wherein, “dismiss” may simply mean removing it from the navigation hierarchy, without animation or changing anything after it, if it’s not the currently showing view controller, “dismissing” from a parentViewController without animation, etc.

I hope this idea helps you give inspiration for how you might do this! :]

Let me know how it goes when you’ve found a solution that works for you.

Cheers,
Joshua