Unverified Commit 38c33d9c authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

Build routes even less. (#58202)

parent eee3912f
...@@ -185,7 +185,6 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> { ...@@ -185,7 +185,6 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> {
} }
break; break;
} }
changedInternalState();
} }
@override @override
...@@ -193,16 +192,19 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> { ...@@ -193,16 +192,19 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> {
assert(!_transitionCompleter.isCompleted, 'Cannot install a $runtimeType after disposing it.'); assert(!_transitionCompleter.isCompleted, 'Cannot install a $runtimeType after disposing it.');
_controller = createAnimationController(); _controller = createAnimationController();
assert(_controller != null, '$runtimeType.createAnimationController() returned null.'); assert(_controller != null, '$runtimeType.createAnimationController() returned null.');
_animation = createAnimation(); _animation = createAnimation()
..addStatusListener(_handleStatusChanged);
assert(_animation != null, '$runtimeType.createAnimation() returned null.'); assert(_animation != null, '$runtimeType.createAnimation() returned null.');
super.install(); super.install();
if (_animation.isCompleted && overlayEntries.isNotEmpty) {
overlayEntries.first.opaque = opaque;
}
} }
@override @override
TickerFuture didPush() { TickerFuture didPush() {
assert(_controller != null, '$runtimeType.didPush called before calling install() or after calling dispose().'); assert(_controller != null, '$runtimeType.didPush called before calling install() or after calling dispose().');
assert(!_transitionCompleter.isCompleted, 'Cannot reuse a $runtimeType after disposing it.'); assert(!_transitionCompleter.isCompleted, 'Cannot reuse a $runtimeType after disposing it.');
_didPushOrReplace();
super.didPush(); super.didPush();
return _controller.forward(); return _controller.forward();
} }
...@@ -211,7 +213,6 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> { ...@@ -211,7 +213,6 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> {
void didAdd() { void didAdd() {
assert(_controller != null, '$runtimeType.didPush called before calling install() or after calling dispose().'); assert(_controller != null, '$runtimeType.didPush called before calling install() or after calling dispose().');
assert(!_transitionCompleter.isCompleted, 'Cannot reuse a $runtimeType after disposing it.'); assert(!_transitionCompleter.isCompleted, 'Cannot reuse a $runtimeType after disposing it.');
_didPushOrReplace();
super.didAdd(); super.didAdd();
_controller.value = _controller.upperBound; _controller.value = _controller.upperBound;
} }
...@@ -222,19 +223,9 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> { ...@@ -222,19 +223,9 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> {
assert(!_transitionCompleter.isCompleted, 'Cannot reuse a $runtimeType after disposing it.'); assert(!_transitionCompleter.isCompleted, 'Cannot reuse a $runtimeType after disposing it.');
if (oldRoute is TransitionRoute) if (oldRoute is TransitionRoute)
_controller.value = oldRoute._controller.value; _controller.value = oldRoute._controller.value;
_didPushOrReplace();
super.didReplace(oldRoute); super.didReplace(oldRoute);
} }
void _didPushOrReplace() {
_animation.addStatusListener(_handleStatusChanged);
// If the animation is already completed, _handleStatusChanged will not get
// a chance to set opaqueness of OverlayEntry.
if (_animation.isCompleted && overlayEntries.isNotEmpty) {
overlayEntries.first.opaque = opaque;
}
}
@override @override
bool didPop(T result) { bool didPop(T result) {
assert(_controller != null, '$runtimeType.didPop called before calling install() or after calling dispose().'); assert(_controller != null, '$runtimeType.didPop called before calling install() or after calling dispose().');
...@@ -856,7 +847,7 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T ...@@ -856,7 +847,7 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
/// ``` /// ```
/// ///
/// The given [BuildContext] will be rebuilt if the state of the route changes /// The given [BuildContext] will be rebuilt if the state of the route changes
/// (specifically, if [isCurrent] or [canPop] change value). /// while it is visible (specifically, if [isCurrent] or [canPop] change value).
@optionalTypeArgs @optionalTypeArgs
static ModalRoute<T> of<T extends Object>(BuildContext context) { static ModalRoute<T> of<T extends Object>(BuildContext context) {
final _ModalScopeStatus widget = context.dependOnInheritedWidgetOfExactType<_ModalScopeStatus>(); final _ModalScopeStatus widget = context.dependOnInheritedWidgetOfExactType<_ModalScopeStatus>();
...@@ -936,7 +927,8 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T ...@@ -936,7 +927,8 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
/// is not wrapped in any transition widgets. /// is not wrapped in any transition widgets.
/// ///
/// The [buildTransitions] method, in contrast to [buildPage], is called each /// The [buildTransitions] method, in contrast to [buildPage], is called each
/// time the [Route]'s state changes (e.g. the value of [canPop]). /// time the [Route]'s state changes while it is visible (e.g. if the value of
/// [canPop] changes on the active route).
/// ///
/// The [buildTransitions] method is typically used to define transitions /// The [buildTransitions] method is typically used to define transitions
/// that animate the new topmost route's comings and goings. When the /// that animate the new topmost route's comings and goings. When the
...@@ -1392,8 +1384,9 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T ...@@ -1392,8 +1384,9 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
/// Whether this route can be popped. /// Whether this route can be popped.
/// ///
/// When this changes, the route will rebuild, and any widgets that used /// When this changes, if the route is visible, the route will
/// [ModalRoute.of] will be notified. /// rebuild, and any widgets that used [ModalRoute.of] will be
/// notified.
bool get canPop => !isFirst || willHandlePopInternally; bool get canPop => !isFirst || willHandlePopInternally;
// Internals // Internals
......
...@@ -1182,7 +1182,50 @@ void main() { ...@@ -1182,7 +1182,50 @@ void main() {
expect(log, <String>['building B', 'building C', 'found C', 'building D']); expect(log, <String>['building B', 'building C', 'found C', 'building D']);
key.currentState.pop<void>(); key.currentState.pop<void>();
await tester.pumpAndSettle(const Duration(milliseconds: 10)); await tester.pumpAndSettle(const Duration(milliseconds: 10));
expect(log, <String>['building B', 'building C', 'found C', 'building D', 'building C', 'found C']); expect(log, <String>['building B', 'building C', 'found C', 'building D']);
});
testWidgets('Routes don\'t rebuild just because their animations ended', (WidgetTester tester) async {
final GlobalKey<NavigatorState> key = GlobalKey<NavigatorState>();
final List<String> log = <String>[];
Route<dynamic> nextRoute = PageRouteBuilder<int>(
pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
log.add('building page 1 - ${ModalRoute.of(context).canPop}');
return const Placeholder();
},
);
await tester.pumpWidget(MaterialApp(
navigatorKey: key,
onGenerateRoute: (RouteSettings settings) {
assert(nextRoute != null);
final Route<dynamic> result = nextRoute;
nextRoute = null;
return result;
},
));
expect(log, <String>['building page 1 - false']);
key.currentState.pushReplacement(PageRouteBuilder<int>(
pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
log.add('building page 2 - ${ModalRoute.of(context).canPop}');
return const Placeholder();
},
));
expect(log, <String>['building page 1 - false']);
await tester.pump();
expect(log, <String>['building page 1 - false', 'building page 2 - false']);
await tester.pump(const Duration(milliseconds: 150));
expect(log, <String>['building page 1 - false', 'building page 2 - false']);
key.currentState.pushReplacement(PageRouteBuilder<int>(
pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
log.add('building page 3 - ${ModalRoute.of(context).canPop}');
return const Placeholder();
},
));
expect(log, <String>['building page 1 - false', 'building page 2 - false']);
await tester.pump();
expect(log, <String>['building page 1 - false', 'building page 2 - false', 'building page 3 - false']);
await tester.pump(const Duration(milliseconds: 200));
expect(log, <String>['building page 1 - false', 'building page 2 - false', 'building page 3 - false']);
}); });
testWidgets('route semantics', (WidgetTester tester) async { testWidgets('route semantics', (WidgetTester tester) async {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment