Route transition record and transition delegate updates
Summary
A new boolean getter isWaitingForExitingDecision
was added
to the route transition record and the isEntering
getter
was renamed to isWaitingForEnteringDecision
.
In the resolve()
method for the transition delegate,
use the isWaitingForExitingDecision
to check if an exiting
route actually needs an explicit decision on how to transition
off the screen. If you try to make a decision for an existing route
that isn’t waiting for a decision, Flutter throws an assertion error.
Context
When the navigator receives a new list of pages, it tries to update its
current routes stack to match the list. However, it requires explicit
decisions on how to transition the route on and off the screen.
Previously, routes that were not in the new list required decisions
on how to transition off the screen. However, we later found out
this is not always true. If a route is popped,
but is still waiting for the popping animation to finish,
this route would sit in the navigator routes stack until
the animation was done. If a page update occurred during this time,
this route exits but doesn’t requires a decision
on how to transition off the screen. Therefore,
isWaitingForExitingDecision
was added to cover that case.
The isEntering
getter is also renamed to
isWaitingForEnteringDecision
to be more descriptive,
and also to make the naming more consistent.
Migration guide
If you implement your own transition delegate, you need to check the
exiting routes using the getter isWaitingForExitingDecision
before you
call markForPop
, markForComplete
, or markForRemove
on them.
You also need to rename all the references from isEntering
to
isWaitingForEnteringDecision
.
Code before migration:
import 'package:flutter/widgets.dart';
class NoAnimationTransitionDelegate extends TransitionDelegate<void> {
@override
Iterable<RouteTransitionRecord> resolve({
List<RouteTransitionRecord> newPageRouteHistory,
Map<RouteTransitionRecord, RouteTransitionRecord> locationToExitingPageRoute,
Map<RouteTransitionRecord, List<RouteTransitionRecord>> pageRouteToPagelessRoutes,
}) {
final List<RouteTransitionRecord> results = <RouteTransitionRecord>[];
for (final RouteTransitionRecord pageRoute in newPageRouteHistory) {
if (pageRoute.isEntering) {
pageRoute.markForAdd();
}
results.add(pageRoute);
}
for (final RouteTransitionRecord exitingPageRoute in locationToExitingPageRoute.values) {
exitingPageRoute.markForRemove();
final List<RouteTransitionRecord> pagelessRoutes = pageRouteToPagelessRoutes[exitingPageRoute];
if (pagelessRoutes != null) {
for (final RouteTransitionRecord pagelessRoute in pagelessRoutes) {
pagelessRoute.markForRemove();
}
}
results.add(exitingPageRoute);
}
return results;
}
}
Code after migration:
import 'package:flutter/widgets.dart';
class NoAnimationTransitionDelegate extends TransitionDelegate<void> {
@override
Iterable<RouteTransitionRecord> resolve({
List<RouteTransitionRecord> newPageRouteHistory,
Map<RouteTransitionRecord, RouteTransitionRecord> locationToExitingPageRoute,
Map<RouteTransitionRecord, List<RouteTransitionRecord>> pageRouteToPagelessRoutes,
}) {
final List<RouteTransitionRecord> results = <RouteTransitionRecord>[];
for (final RouteTransitionRecord pageRoute in newPageRouteHistory) {
// Renames isEntering to isWaitingForEnteringDecision.
if (pageRoute.isWaitingForEnteringDecision) {
pageRoute.markForAdd();
}
results.add(pageRoute);
}
for (final RouteTransitionRecord exitingPageRoute in locationToExitingPageRoute.values) {
// Checks the isWaitingForExitingDecision before calling the markFor methods.
if (exitingPageRoute.isWaitingForExitingDecision) {
exitingPageRoute.markForRemove();
final List<RouteTransitionRecord> pagelessRoutes = pageRouteToPagelessRoutes[exitingPageRoute];
if (pagelessRoutes != null) {
for (final RouteTransitionRecord pagelessRoute in pagelessRoutes) {
pagelessRoute.markForRemove();
}
}
}
results.add(exitingPageRoute);
}
return results;
}
}
Timeline
Landed in version: 1.18.0
In stable release: 1.20
References
API documentation:
Relevant issue:
Relevant PR:
- PR 55998: Fixes the navigator pages update crash when there is still a route waiting