Commit dd40d0e2 authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

Modal barrier shouldn't paint when the route is offstage. (#11347)

Fixes https://github.com/flutter/flutter/issues/11323
parent 8f56f6fd
...@@ -443,10 +443,10 @@ typedef bool RoutePredicate(Route<dynamic> route); ...@@ -443,10 +443,10 @@ typedef bool RoutePredicate(Route<dynamic> route);
/// ///
/// ### Popup routes /// ### Popup routes
/// ///
/// Routes don't have to obscure the entire screen. [PopupRoute]s cover /// Routes don't have to obscure the entire screen. [PopupRoute]s cover the
/// the screen with a barrierColor that can be only partially opaque to /// screen with a [ModalRoute.barrierColor] that can be only partially opaque to
/// allow the current screen to show through. Popup routes are "modal" /// allow the current screen to show through. Popup routes are "modal" because
/// because they block input to the widgets below. /// they block input to the widgets below.
/// ///
/// There are functions which create and show popup routes. For /// There are functions which create and show popup routes. For
/// example: [showDialog], [showMenu], and [showModalBottomSheet]. These /// example: [showDialog], [showMenu], and [showModalBottomSheet]. These
......
...@@ -722,6 +722,9 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T ...@@ -722,6 +722,9 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
/// The color to use for the modal barrier. If this is null, the barrier will /// The color to use for the modal barrier. If this is null, the barrier will
/// be transparent. /// be transparent.
///
/// The color is ignored, and the barrier made invisible, when [offstage] is
/// true.
Color get barrierColor; Color get barrierColor;
/// Whether the route should remain in memory when it is inactive. If this is /// Whether the route should remain in memory when it is inactive. If this is
...@@ -741,6 +744,9 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T ...@@ -741,6 +744,9 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
/// non-interactive, but each widget has its final size and position. This /// non-interactive, but each widget has its final size and position. This
/// mechanism lets the [HeroController] determine the final local of any hero /// mechanism lets the [HeroController] determine the final local of any hero
/// widgets being animated as part of the transition. /// widgets being animated as part of the transition.
///
/// The modal barrier, if any, is not rendered if [offstage] is true (see
/// [barrierColor]).
bool get offstage => _offstage; bool get offstage => _offstage;
bool _offstage = false; bool _offstage = false;
set offstage(bool value) { set offstage(bool value) {
...@@ -910,7 +916,7 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T ...@@ -910,7 +916,7 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
// one of the builders // one of the builders
Widget _buildModalBarrier(BuildContext context) { Widget _buildModalBarrier(BuildContext context) {
Widget barrier; Widget barrier;
if (barrierColor != null) { if (barrierColor != null && !offstage) {
assert(barrierColor != _kTransparent); assert(barrierColor != _kTransparent);
final Animation<Color> color = new ColorTween( final Animation<Color> color = new ColorTween(
begin: _kTransparent, begin: _kTransparent,
......
...@@ -27,7 +27,7 @@ class TestTransition extends AnimatedWidget { ...@@ -27,7 +27,7 @@ class TestTransition extends AnimatedWidget {
} }
class TestRoute<T> extends PageRoute<T> { class TestRoute<T> extends PageRoute<T> {
TestRoute({ this.child, RouteSettings settings }) : super(settings: settings); TestRoute({ this.child, RouteSettings settings, this.barrierColor }) : super(settings: settings);
final Widget child; final Widget child;
...@@ -35,7 +35,7 @@ class TestRoute<T> extends PageRoute<T> { ...@@ -35,7 +35,7 @@ class TestRoute<T> extends PageRoute<T> {
Duration get transitionDuration => const Duration(milliseconds: 150); Duration get transitionDuration => const Duration(milliseconds: 150);
@override @override
Color get barrierColor => null; final Color barrierColor;
@override @override
bool get maintainState => false; bool get maintainState => false;
...@@ -180,4 +180,31 @@ void main() { ...@@ -180,4 +180,31 @@ void main() {
expect(state(skipOffstage: false), equals('G')); // route 1 is not around any more expect(state(skipOffstage: false), equals('G')); // route 1 is not around any more
}); });
testWidgets('Check onstage/offstage handling of barriers around transitions', (WidgetTester tester) async {
await tester.pumpWidget(
new MaterialApp(
onGenerateRoute: (RouteSettings settings) {
switch (settings.name) {
case '/': return new TestRoute<Null>(settings: settings, child: const Text('A'));
case '/1': return new TestRoute<Null>(settings: settings, barrierColor: const Color(0xFFFFFF00), child: const Text('B'));
}
}
)
);
expect(find.byType(ModalBarrier), findsOneWidget);
tester.state<NavigatorState>(find.byType(Navigator)).pushNamed('/1');
expect(find.byType(ModalBarrier), findsOneWidget);
await tester.pump();
expect(find.byType(ModalBarrier), findsNWidgets(2));
expect(tester.widget<ModalBarrier>(find.byType(ModalBarrier).first).color, isNull);
expect(tester.widget<ModalBarrier>(find.byType(ModalBarrier).last).color, isNull);
await tester.pump(const Duration(seconds: 1));
expect(find.byType(ModalBarrier), findsOneWidget);
expect(tester.widget<ModalBarrier>(find.byType(ModalBarrier)).color, const Color(0xFFFFFF00));
});
} }
...@@ -200,7 +200,7 @@ void main() { ...@@ -200,7 +200,7 @@ void main() {
expect(settingsOffset.dy, 100.0); expect(settingsOffset.dy, 100.0);
}); });
testWidgets('Check back gesture doesnt start during transitions', (WidgetTester tester) async { testWidgets('Check back gesture doesn\'t start during transitions', (WidgetTester tester) async {
final GlobalKey containerKey1 = new GlobalKey(); final GlobalKey containerKey1 = new GlobalKey();
final GlobalKey containerKey2 = new GlobalKey(); final GlobalKey containerKey2 = new GlobalKey();
final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{ final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
......
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