Unverified Commit fdab8546 authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

Minor doc, style, and perf updates to Navigator/Routes (#71689)

* Minor doc, style, and perf updates to Navigator/Routes

These are minor fixes I ended up making while working on a larger
project that never went anywhere.

- Used a ColoredBox instead of a DecoratedBox for ModalBarrier
  (probably a trivial memory/perf win).

- A bunch of Navigator documentation fixes around when things rebuild.

- Mark routes dirty when the Navigator has a dependency change. I
  cannot find a way to test this because as far as I can tell it makes
  no actual difference to when things rebuild because whenever the
  Navigator rebuilds the Overlay rebuilds and whenever that happens
  every OverlayEntry rebuilds, but in theory that's not guaranteed so
  this is sort of a correctness fix. It may even be a perf loss. We do
  something similar in didUpdateWidget already. I could be convinced
  to maybe remove these...

- Make ModalRoute.filter public like everything else.

- Made ModalRoute update its barrier when it gets an update, in case
  e.g. the modal barrier depends on inherited widgets via the
  navigator context. Again, not sure of any way to detect this, it
  might actually be moot, but it seems to be the technically correct
  solution?

- Minor style fixes.

All in all I couldn't figure out a way to test any of this (I wrote
multiple large tests but it turns out they all already pass on master
and are effectively redundant with existing tests).

* Remove extraneous blank line
parent 50dfd137
......@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:convert';
import 'dart:typed_data';
......
......@@ -8,7 +8,6 @@ import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'basic.dart';
import 'container.dart';
import 'debug.dart';
import 'framework.dart';
import 'gesture_detector.dart';
......@@ -113,10 +112,8 @@ class ModalBarrier extends StatelessWidget {
opaque: true,
child: ConstrainedBox(
constraints: const BoxConstraints.expand(),
child: color == null ? null : DecoratedBox(
decoration: BoxDecoration(
color: color,
),
child: color == null ? null : ColoredBox(
color: color!,
),
),
),
......
......@@ -399,20 +399,30 @@ abstract class Route<T> {
///
/// See also:
///
/// * [changedExternalState], which is called when the [Navigator] rebuilds.
/// * [changedExternalState], which is called when the [Navigator] has
/// updated in some manner that might affect the routes.
@protected
@mustCallSuper
void changedInternalState() { }
/// Called whenever the [Navigator] has its widget rebuilt, to indicate that
/// the route may wish to rebuild as well.
/// Called whenever the [Navigator] has updated in some manner that might
/// affect routes, to indicate that the route may wish to rebuild as well.
///
/// This is called by the [Navigator] whenever the [NavigatorState]'s
/// [State.widget] changes, for example because the [MaterialApp] has been rebuilt.
/// This ensures that routes that directly refer to the state of the widget
/// that built the [MaterialApp] will be notified when that widget rebuilds,
/// since it would otherwise be difficult to notify the routes that state they
/// depend on may have changed.
/// This is called by the [Navigator] whenever the
/// [NavigatorState]'s [State.widget] changes (as in [State.didUpdateWidget]),
/// for example because the [MaterialApp] has been rebuilt. This
/// ensures that routes that directly refer to the state of the
/// widget that built the [MaterialApp] will be notified when that
/// widget rebuilds, since it would otherwise be difficult to notify
/// the routes that state they depend on may have changed.
///
/// It is also called whenever the [Navigator]'s dependencies change
/// (as in [State.didChangeDependencies]). This allows routes to use the
/// [Navigator]'s context ([NavigatorState.context]), for example in
/// [ModalRoute.barrierColor], and update accordingly.
///
/// The [ModalRoute] subclass overrides this to force the barrier
/// overlay to rebuild.
///
/// See also:
///
......@@ -3442,6 +3452,8 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin, Res
void didChangeDependencies() {
super.didChangeDependencies();
_updateHeroController(HeroControllerScope.of(context));
for (final _RouteEntry entry in _history)
entry.route.changedExternalState();
}
void _updateHeroController(HeroController? newHeroController) {
......
......@@ -871,15 +871,14 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
/// Creates a route that blocks interaction with previous routes.
ModalRoute({
RouteSettings? settings,
ui.ImageFilter? filter,
}) : _filter = filter,
super(settings: settings);
this.filter,
}) : super(settings: settings);
/// The filter to add to the barrier.
///
/// If given, this filter will be applied to the modal barrier using
/// [BackdropFilter]. This allows blur effects, for example.
final ui.ImageFilter? _filter;
final ui.ImageFilter? filter;
// The API for general users of this class
......@@ -1130,9 +1129,14 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
///
/// If [barrierDismissible] is false, then tapping the barrier has no effect.
///
/// If this getter would ever start returning a different value, the
/// [Route.changedInternalState] should be invoked so that the change can take
/// effect.
/// If this getter would ever start returning a different value,
/// either [changedInternalState] or [changedExternalState] should
/// be invoked so that the change can take effect.
///
/// It is safe to use `navigator.context` to look up inherited
/// widgets here, because the [Navigator] calls
/// [changedExternalState] whenever its dependencies change, and
/// [changedExternalState] causes the modal barrier to rebuild.
///
/// See also:
///
......@@ -1154,6 +1158,15 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
/// If [semanticsDismissible] is false, then modal barrier semantics are
/// excluded from the semantics tree and tapping on the modal barrier
/// has no effect.
///
/// If this getter would ever start returning a different value,
/// either [changedInternalState] or [changedExternalState] should
/// be invoked so that the change can take effect.
///
/// It is safe to use `navigator.context` to look up inherited
/// widgets here, because the [Navigator] calls
/// [changedExternalState] whenever its dependencies change, and
/// [changedExternalState] causes the modal barrier to rebuild.
bool get semanticsDismissible => true;
/// {@template flutter.widgets.ModalRoute.barrierColor}
......@@ -1174,22 +1187,24 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
/// transparent to the specified color.
/// {@endtemplate}
///
/// If this getter would ever start returning a different color, the
/// [Route.changedInternalState] should be invoked so that the change can take
/// effect.
/// If this getter would ever start returning a different color, one
/// of the [changedInternalState] or [changedExternalState] methods
/// should be invoked so that the change can take effect.
///
/// It is safe to use `navigator.context` to look up inherited
/// widgets here, because the [Navigator] calls
/// [changedExternalState] whenever its dependencies change, and
/// [changedExternalState] causes the modal barrier to rebuild.
///
/// {@tool snippet}
///
/// It is safe to use `navigator.context` here. For example, to make
/// the barrier color use the theme's background color, one could say:
/// For example, to make the barrier color use the theme's
/// background color, one could say:
///
/// ```dart
/// Color get barrierColor => Theme.of(navigator.context).backgroundColor;
/// ```
///
/// The [Navigator] causes the [ModalRoute]'s modal barrier overlay entry
/// to rebuild any time its dependencies change.
///
/// {@end-tool}
///
/// See also:
......@@ -1213,9 +1228,14 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
/// usually darkened by the modal barrier.
/// {@endtemplate}
///
/// If this getter would ever start returning a different label, the
/// [Route.changedInternalState] should be invoked so that the change can take
/// effect.
/// If this getter would ever start returning a different label,
/// either [changedInternalState] or [changedExternalState] should
/// be invoked so that the change can take effect.
///
/// It is safe to use `navigator.context` to look up inherited
/// widgets here, because the [Navigator] calls
/// [changedExternalState] whenever its dependencies change, and
/// [changedExternalState] causes the modal barrier to rebuild.
///
/// See also:
///
......@@ -1236,9 +1256,14 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
/// While the route is animating into position, the color is animated from
/// transparent to the specified [barrierColor].
///
/// If this getter would ever start returning a different curve, the
/// [changedInternalState] should be invoked so that the change can take
/// effect.
/// If this getter would ever start returning a different curve,
/// either [changedInternalState] or [changedExternalState] should
/// be invoked so that the change can take effect.
///
/// It is safe to use `navigator.context` to look up inherited
/// widgets here, because the [Navigator] calls
/// [changedExternalState] whenever its dependencies change, and
/// [changedExternalState] causes the modal barrier to rebuild.
///
/// It defaults to [Curves.ease].
///
......@@ -1451,6 +1476,7 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
@override
void changedExternalState() {
super.changedExternalState();
_modalBarrier.markNeedsBuild();
if (_scopeKey.currentState != null)
_scopeKey.currentState!._forceRebuildPage();
}
......@@ -1493,9 +1519,9 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
barrierSemanticsDismissible: semanticsDismissible,
);
}
if (_filter != null) {
if (filter != null) {
barrier = BackdropFilter(
filter: _filter!,
filter: filter!,
child: barrier,
);
}
......
......@@ -1039,7 +1039,7 @@ void main() {
final dynamic renderObject = tester.renderObject(find.byType(Overlay));
expect(renderObject.clipBehavior, equals(Clip.hardEdge));
for(final Clip clip in Clip.values) {
for (final Clip clip in Clip.values) {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
......
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