Animate change of view controllers without using navigation controller stack, subviews or modal controllers?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
If you do not want to use a navigation controller push, a modal presentation, or a hand-built container hierarchy, the cleanest way to animate between screens is usually to replace the window's rootViewController with a transition animation. This is useful for flows such as login to main app, onboarding completion, or a full reset of the visible UI.
Replace the window root controller with animation
A navigation controller is designed for stack-based movement, but some transitions are not stack changes at all. If the old screen should disappear completely and the new screen should become the fresh top-level interface, swap the root controller.
This pattern makes the change feel animated while still treating the destination as a new application root.
Using UIView.transition for a simpler crossfade
If you do not need a custom snapshot animation, UIView.transition is even simpler:
This gives you a clean full-screen transition without introducing a navigation stack or modal relationship.
When this approach is the right fit
This strategy is best when the new view controller should replace the old app state rather than sit on top of it.
Common examples include:
- login screen to authenticated app shell,
- onboarding flow to home screen,
- logout flow back to authentication,
- or switching between two completely separate UI shells.
In these cases, a push animation can be semantically wrong because there is no meaningful "back" relationship.
How to create the destination controller
You can still instantiate the new controller from a storyboard if needed:
The important point is not how the controller is created. The important point is that the transition occurs by replacing the window root, not by pushing or presenting.
Why not manually move random controller views around
Developers sometimes try to animate between controllers by removing one controller's view and adding another controller's view directly to the hierarchy. That usually leads to lifecycle problems because the view controller containment rules are no longer being respected.
If you truly need both controllers alive at once, use a proper custom container. But if you only need a full-screen replacement, swapping the root controller is usually cleaner.
Common Pitfalls
The most common mistake is using root-controller replacement for screens that really should support back navigation. If the user expects to return to the previous screen, a navigation controller is the better tool.
Another issue is forgetting to keep a valid UIWindow reference. In multi-scene apps, code that assumes a single global window may fail or update the wrong scene.
Be careful with app state too. Replacing the root controller resets the visible hierarchy, so any temporary state stored in the old flow disappears unless you pass it explicitly.
Finally, do not animate controller views manually without understanding containment. If two controllers are both active in the hierarchy, use proper child view controller APIs instead of raw subview swapping.
Summary
- If the transition is a full UI handoff, replacing the window
rootViewControlleris a strong option. - '
UIView.transitiongives a simple animated root swap without navigation or modal presentation.' - Snapshot-based animation allows more custom visual effects.
- This technique fits login, onboarding, and app-shell transitions better than stack navigation.
- If both controllers must coexist, use a real container controller instead of ad hoc view swapping.

