[Breaking Change Proposal] Routes and Navigator Refactor

543 views
Skip to first unread message

Chun-Heng Tai

unread,
Jan 28, 2020, 3:32:42 PM1/28/20
to flutt...@googlegroups.com, flutter-...@googlegroups.com

If your app does not rely on the return value of Navigator.pop, manage the life cycles of the overlay entries of routes, override Route.install, or rely on the isInitialRoute in RouteSetting, you can stop reading now.

 

Summary

While we are refactoring Navigator according to this design document, we would like to make several changes to our current apis.

 

Firstly, we would like to change the function signature of Navigator.pop to return void instead of a boolean value.

 

Secondly, we would like to change the function signature of Route.install to not take positional argument insertionPoint, as well as the overlayEntries must have at least one overlay entry after Route.install is called.

 

Thirdly, the Route.dispose will not remove its overlayEntries from the overlay. The Navigator that owns the route will be in charge of adding and removing its overlay entries from overlay

 

Finally, we also would like to deprecate isInitialRoute and eventually remove it once the page api is added to the framework.

 

For more information, please refer to the design document.

Change PR

Issue tracker

Justification

The boolean return value of the Navigator.pop is not well defined and user can achieve the same result by calling the Navigator.canPop. Since the api of Navigator.canPop is better defined, we would like to simplify the Navigator.pop to not return the boolean value.

 

While we are refactoring navigator for the upcoming page api, the navigator would require the ability to manually rearrange overlay entries in the overlay to allow user to change routes history use the new api. Our current structure does not allow it because the route manages its own overlay entries in the overlay, and the navigator does not access them directly. We would like to change it so that the route only creates and destroys its overlay entries while the navigator inserts or removes overlay entries from the overlay. This change also makes the insertionPoint argument of Route.install obsolete, and we would like to remove it as part of this breaking change.

 

The page api also provides the ability to reorder initial routes. This will make isInitialRoute inconsistent during the app's lifetime. An initial route might become non-initial route and vise-versa, and a route will need to be rebuilt if its RouteSetting has been updated. Changing the route history will cause all the routes to be rebuilt, and that defeat the purpose of the page api. We would like to remove the isInitialRoute property from the RouteSetting, so that the current route structure will still work with the new api.

Related Issues

https://github.com/flutter/flutter/issues/45938

 

How to migrate

Case 1: An app has dependency of pop to return a boolean value

TextField(

onTap: () {

             if (Navigator.pop(context))

             print(‘There still is at least one route after pop’);

Else

print(‘Oops! No more route.’);

            }

)

 

After migration:

TextField(

onTap: () {

             if (Navigator.canPop(context))

             print(‘There still is at least one route after pop’);

Else

print(‘Oops! No more route.’);

// Our navigator will pop the route anyway.

Navigator.pop(context);

            }

)

 

Case2: An app generate routes based on isInitialRoute

 

MaterialApp(

onGenerateRoute: (RouteSetting setting) {

if (setting.isInitialRoute)

return FakeSplashRoute();

else

return RealRoute(setting);

}

)

There are different ways to migrate this app. One way is to make sure to set initial route name to a fixed value and generate a specific route (FakeSplashRoute in the above example) for the route name.

 

MaterialApp(

           initialRouteName: ‘fakeSplash’,

onGenerateRoute: (RouteSetting setting) {

if (setting.name == ‘fakeSplash’)

return FakeSplashRoute();

else

return RealRoute(setting);

}

)

 

If there is a more complicated use case, we provide a new api, onGenerateInitialRoutes, in MaterialApp/CupertinoApp.

 

MaterialApp(

onGenerateRoute: (RouteSetting setting) {

return RealRoute(setting);

},

onGenerateInitialRoutes: (String initialRouteName) {

return <Route>[FakeSplashRoute()];

}

)

 

 

If you have any issues migrating or questions about this change, feel free to comment on the issue.

 

Cheers,

Chun-Heng


ch...@google.com

unread,
Feb 26, 2020, 7:16:06 PM2/26/20
to Flutter Public Announcements (flutter-announce)
If your app does not use pushpushAndRemoveUntilpushNamedpushNamedAndRemoveUntil,  pushReplacement, and pushReplacementNamed with route that has isInitialRoute set to true, you can stop reading now.

As a follow up, the change has landed. However, this refactoring also included a bug fix that was not discussed in the previous announcement.

It has been brought up by this comment. When pushing a route with isInitialRoute set to true, the route will be pushed without transition as if it is an initial route. This is not an intended behavior and was fixed as part of the refactor. If your app is relying on this to reset the routes history without animation, there is currently no straight forward way to migrate. One possible way will be using replace and removeRoute, but that might not work for every use cases. A part of the Navigator 2.0 is to solve this problem and give developer the freedom to manage their routes history with or without transition.

Feel free to comment on this issue if you have any questions.

Chun-Heng.
Reply all
Reply to author
Forward
0 new messages