To understand PopupRoute we need to start at the very beginning. What even is a Route ?

Routing is at the core of all apps. Popups, pages/screens, dialogs all use routes in one form or another. In Flutter, there are four types of routes:

Route

OverlayRoute

TransitionRoute

Modal Route

Popup Route

Route

Route is the base class used by all routes in Flutter. It is an abstract class which defines an interface for interaction with the Navigator . It contains properties for whether the page/screen is active and at the top of the navigator stack or inactive and at the bottom. Getters are also defined for retrieving the result when the route is "popped" by the Navigator and the current list of overlay entries used by this route (more on the overlay stuff later).

Also defined in Route are methods for handling rebuilds, state change, changes to the next and previous route in the stack and callbacks for when the route is popped.

Below shows a full list of the available methods and their functionality:

Overlay Route

Next, we move to OverlayRoute . As the name suggests, an OverlayRoute is a route that displays widgets in the Navigator overlay, above the current route. The constructor of this class takes on an optional parameter, RouteSettings which is passed to the superclass, Route .

Included in this class are two additional properties, finishedWhenPopped and overlayEntries . finishedWhenPopped returns a true when didPop successfully removes or "pops" the route and it is disposed of by the Navigator . Overlay entries, on the other hand, is a list of entries the route has placed on the Overlay .

What is an Overlay

A section talking about OverlayRoute would not be complete without mentioning Overlay and OverlayEntry . An overlay in Flutter is a Stateful widget that contains a list of the onstage and offstage children. The class Overlay takes an optional list of overlay entries, initialEntries . If no entries are specified, an empty List is automatically created. Also in this class is a static of method for retrieving the closest instance of OverlayState . This is useful since if you'd like to add an overlay to the screen, you'd need to call the insert method located in the state class.

The real magic happens in the state class. Here, two very important methods exist, insert and insertAll . When the state is first created, the initialEntries are added using the insertAll method. As you might've guessed, this method takes an Iterable of overlay entries. The elements in this Iterable check whether they should be inserted above another entry (passed to insertAll as an optional parameter) then inserted into the current list of entries at the appropriate index. The process is pretty much the same for the insert method, only this time there is no need to loop over any list.

What is an Overlay Entry

At this point, you’ve probably seen the term “overlayEntry” quite a lot. Let’s take a few minutes to briefly have a look at it since it is the foundation of the Overlay class, after all, it is the class that is being inserted and removed everywhere.

An Overlay Entry is a class which contains a WidgetBuilder and

Transition Route: Animations 🎉

What’s the one thing missing from routes at this point? Animations of course!

Transition route as the name implies, adds entrance and exit animations to routes. It creates and manages an AnimationController which is used to drive the transition. The controller , animation and duration are all exposed via getters.

Transition Route contains a Completer which is used to check whether the transition is finished or if the overlay entries have been removed from the navigator's overlay. The future also completes once the animation has been dismissed after popped was called. Both createAnimationController and createAnimation utilize this completer to ensure the route is not disposed of before carrying out their function.

The various animation statues are handled internally by the function _handleStatusChanged . A completed animation changes the opaque value of the first overlay entry to reflect that of the opaque value passed by the user. Should the route be opaque, the route behind it will not be built in an attempt to save resources. Both reverse and forward statuses check the overlayEntries to ensure they are not empty then set the opaque value of the first overlay entry to false. This is done since while the route is being animated, the previous one will still be visible. The final animation status dismissed checks to make sure the route is not active before calling navigator.finalizeRoute to properly dispose and remove the route.

Modal Route

Implemented by PageRoute and PopupRoute , a modal route simply block all interaction with the previous route. That said, not all ModalRoute is opaque. Popups such as dialog boxes and menus can overlap the previous route without hiding the content that is beneath it.

Modal routes also take a <T> argument that is used as the return value of the route. Should there be no return value, it is recommended that you use void as the return value.

Like the classes before it, ModalRoute also exposes additional properties to the user. The ability to control how the route is dismissed, the label and color of the barrier, whether the route should maintain its state when inactive and the primary and secondary animations are just some of the noteworthy properties exposed.

Defined in the class ModalRoute are the methods buildTransitions and buildPage . As the names imply, build transitions is used to animate the static content of the page. This method is called every time the route state changes. Since its primary purpose is for animations, you should avoid building static content in this method, buildPage should be used instead since it would be more efficient.

Build Transitions takes the following properties:

Note: The child property passed to this function is the result/return value of buildPage .

Build Page as mentioned earlier is used to build the static content of the page. The primary content of the route is built using this method. It is called when the route is first built and is rarely (if ever) called after that point. Unlike buildTransitions , it is not automatically called when the state changes unless ModalRoute.of is used.