Added onDismiss
callback to ModalBarrier. (#83860)
This commit is contained in:
parent
3fba55a18d
commit
6ea0b2c929
@ -34,6 +34,7 @@ class ModalBarrier extends StatelessWidget {
|
||||
Key? key,
|
||||
this.color,
|
||||
this.dismissible = true,
|
||||
this.onDismiss,
|
||||
this.semanticsLabel,
|
||||
this.barrierSemanticsDismissible = true,
|
||||
}) : super(key: key);
|
||||
@ -46,7 +47,12 @@ class ModalBarrier extends StatelessWidget {
|
||||
/// [ModalBarrier] built by [ModalRoute] pages.
|
||||
final Color? color;
|
||||
|
||||
/// Whether touching the barrier will pop the current route off the [Navigator].
|
||||
/// Specifies if the barrier will be dismissed when the user taps on it.
|
||||
///
|
||||
/// If true, and [onDismiss] is non-null, [onDismiss] will be called,
|
||||
/// otherwise the current route will be popped from the ambient [Navigator].
|
||||
///
|
||||
/// If false, tapping on the barrier will do nothing.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
@ -54,6 +60,16 @@ class ModalBarrier extends StatelessWidget {
|
||||
/// [ModalBarrier] built by [ModalRoute] pages.
|
||||
final bool dismissible;
|
||||
|
||||
/// Called when the barrier is being dismissed.
|
||||
///
|
||||
/// If non-null [onDismiss] will be called in place of popping the current
|
||||
/// route. It is up to the callback to handle dismissing the barrier.
|
||||
///
|
||||
/// If null, the ambient [Navigator]'s current route will be popped.
|
||||
///
|
||||
/// This field is ignored if [dismissible] is false.
|
||||
final VoidCallback? onDismiss;
|
||||
|
||||
/// Whether the modal barrier semantics are included in the semantics tree.
|
||||
///
|
||||
/// See also:
|
||||
@ -94,7 +110,15 @@ class ModalBarrier extends StatelessWidget {
|
||||
final bool modalBarrierSemanticsDismissible = barrierSemanticsDismissible ?? semanticsDismissible;
|
||||
|
||||
void handleDismiss() {
|
||||
Navigator.maybePop(context);
|
||||
if (dismissible) {
|
||||
if (onDismiss != null) {
|
||||
onDismiss!();
|
||||
} else {
|
||||
Navigator.maybePop(context);
|
||||
}
|
||||
} else {
|
||||
SystemSound.play(SystemSoundType.alert);
|
||||
}
|
||||
}
|
||||
|
||||
return BlockSemantics(
|
||||
@ -103,12 +127,7 @@ class ModalBarrier extends StatelessWidget {
|
||||
// modal barriers are not dismissible in accessibility mode.
|
||||
excluding: !semanticsDismissible || !modalBarrierSemanticsDismissible,
|
||||
child: _ModalBarrierGestureDetector(
|
||||
onDismiss: () {
|
||||
if (dismissible)
|
||||
handleDismiss();
|
||||
else
|
||||
SystemSound.play(SystemSoundType.alert);
|
||||
},
|
||||
onDismiss: handleDismiss,
|
||||
child: Semantics(
|
||||
label: semanticsDismissible ? semanticsLabel : null,
|
||||
onDismiss: semanticsDismissible ? handleDismiss : null,
|
||||
|
@ -365,6 +365,60 @@ void main() {
|
||||
expect(willPopCalled, isTrue);
|
||||
});
|
||||
|
||||
testWidgets('ModalBarrier will call onDismiss callback', (WidgetTester tester) async {
|
||||
bool dismissCallbackCalled = false;
|
||||
final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
|
||||
'/': (BuildContext context) => const FirstWidget(),
|
||||
'/modal': (BuildContext context) => SecondWidget(onDismiss: () {
|
||||
dismissCallbackCalled = true;
|
||||
}),
|
||||
};
|
||||
|
||||
await tester.pumpWidget(MaterialApp(routes: routes));
|
||||
|
||||
// Initially the barrier is not visible
|
||||
expect(find.byKey(const ValueKey<String>('barrier')), findsNothing);
|
||||
|
||||
// Tapping on X routes to the barrier
|
||||
await tester.tap(find.text('X'));
|
||||
await tester.pump(); // begin transition
|
||||
await tester.pump(const Duration(seconds: 1)); // end transition
|
||||
expect(find.byKey(const ValueKey<String>('barrier')), findsOneWidget);
|
||||
expect(dismissCallbackCalled, false);
|
||||
|
||||
// Tap on the barrier
|
||||
await tester.tap(find.byKey(const ValueKey<String>('barrier')));
|
||||
await tester.pumpAndSettle(const Duration(seconds: 1)); // end transition
|
||||
expect(dismissCallbackCalled, true);
|
||||
});
|
||||
|
||||
testWidgets('ModalBarrier will not pop when given an onDismiss callback', (WidgetTester tester) async {
|
||||
final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
|
||||
'/': (BuildContext context) => const FirstWidget(),
|
||||
'/modal': (BuildContext context) => SecondWidget(onDismiss: () {}),
|
||||
};
|
||||
|
||||
await tester.pumpWidget(MaterialApp(routes: routes));
|
||||
|
||||
// Initially the barrier is not visible
|
||||
expect(find.byKey(const ValueKey<String>('barrier')), findsNothing);
|
||||
|
||||
// Tapping on X routes to the barrier
|
||||
await tester.tap(find.text('X'));
|
||||
await tester.pump(); // begin transition
|
||||
await tester.pump(const Duration(seconds: 1)); // end transition
|
||||
expect(find.byKey(const ValueKey<String>('barrier')), findsOneWidget);
|
||||
|
||||
// Tap on the barrier
|
||||
await tester.tap(find.byKey(const ValueKey<String>('barrier')));
|
||||
await tester.pumpAndSettle(const Duration(seconds: 1)); // end transition
|
||||
expect(
|
||||
find.byKey(const ValueKey<String>('barrier')),
|
||||
findsOneWidget,
|
||||
reason: 'The route should not have been dismissed by tapping the barrier, as there was a onDismiss callback given.',
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Undismissible ModalBarrier hidden in semantic tree', (WidgetTester tester) async {
|
||||
final SemanticsTester semantics = SemanticsTester(tester);
|
||||
await tester.pumpWidget(const ModalBarrier(dismissible: false));
|
||||
@ -442,11 +496,15 @@ class FirstWidget extends StatelessWidget {
|
||||
}
|
||||
|
||||
class SecondWidget extends StatelessWidget {
|
||||
const SecondWidget({ Key? key }) : super(key: key);
|
||||
const SecondWidget({ Key? key, this.onDismiss }) : super(key: key);
|
||||
|
||||
final VoidCallback? onDismiss;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const ModalBarrier(
|
||||
key: ValueKey<String>('barrier'),
|
||||
return ModalBarrier(
|
||||
key: const ValueKey<String>('barrier'),
|
||||
onDismiss: onDismiss,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user