Added 'barrierColor' and 'useSafeArea' parameters to showDialog. (#54110)
diff --git a/packages/flutter/lib/src/material/dialog.dart b/packages/flutter/lib/src/material/dialog.dart
index be0f638..dc1b79a 100644
--- a/packages/flutter/lib/src/material/dialog.dart
+++ b/packages/flutter/lib/src/material/dialog.dart
@@ -871,10 +871,23 @@
/// the dialog. It is only used when the method is called. Its corresponding
/// widget can be safely removed from the tree before the dialog is closed.
///
+/// The `barrierDismissible` argument is used to indicate whether tapping on the
+/// barrier will dismiss the dialog. It is `true` by default and can not be `null`.
+///
+/// The `barrierColor` argument is used to specify the color of the modal
+/// barrier that darkens everything the dialog. If `null` the default color
+/// `Colors.black54` is used.
+///
+/// The `useSafeArea` argument is used to indicate if the dialog should only
+/// display in 'safe' areas of the screen not used by the operating system
+/// (see [SafeArea] for more details). It is `true` by default which will mean
+/// the dialog will not overlap operating system areas. If it is set to `false`
+/// the dialog will only be constrained by the screen size. It can not be 'null`.
+//
/// The `useRootNavigator` argument is used to determine whether to push the
/// dialog to the [Navigator] furthest from or nearest to the given `context`.
/// By default, `useRootNavigator` is `true` and the dialog route created by
-/// this method is pushed to the root navigator.
+/// this method is pushed to the root navigator. It can not be `null`.
///
/// The `routeSettings` argument is passed to [showGeneralDialog],
/// see [RouteSettings] for details.
@@ -897,7 +910,12 @@
/// * <https://material.io/design/components/dialogs.html>
Future<T> showDialog<T>({
@required BuildContext context,
+ WidgetBuilder builder,
bool barrierDismissible = true,
+ Color barrierColor,
+ bool useSafeArea = true,
+ bool useRootNavigator = true,
+ RouteSettings routeSettings,
@Deprecated(
'Instead of using the "child" argument, return the child from a closure '
'provided to the "builder" argument. This will ensure that the BuildContext '
@@ -905,11 +923,10 @@
'This feature was deprecated after v0.2.3.'
)
Widget child,
- WidgetBuilder builder,
- bool useRootNavigator = true,
- RouteSettings routeSettings,
}) {
assert(child == null || builder == null);
+ assert(barrierDismissible != null);
+ assert(useSafeArea != null);
assert(useRootNavigator != null);
assert(debugCheckHasMaterialLocalizations(context));
@@ -918,19 +935,21 @@
context: context,
pageBuilder: (BuildContext buildContext, Animation<double> animation, Animation<double> secondaryAnimation) {
final Widget pageChild = child ?? Builder(builder: builder);
- return SafeArea(
- child: Builder(
- builder: (BuildContext context) {
- return theme != null
- ? Theme(data: theme, child: pageChild)
- : pageChild;
- }
- ),
+ Widget dialog = Builder(
+ builder: (BuildContext context) {
+ return theme != null
+ ? Theme(data: theme, child: pageChild)
+ : pageChild;
+ }
);
+ if (useSafeArea) {
+ dialog = SafeArea(child: dialog);
+ }
+ return dialog;
},
barrierDismissible: barrierDismissible,
barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
- barrierColor: Colors.black54,
+ barrierColor: barrierColor ?? Colors.black54,
transitionDuration: const Duration(milliseconds: 150),
transitionBuilder: _buildMaterialDialogTransitions,
useRootNavigator: useRootNavigator,
diff --git a/packages/flutter/test/material/dialog_test.dart b/packages/flutter/test/material/dialog_test.dart
index 2bd1161..9d579bb 100644
--- a/packages/flutter/test/material/dialog_test.dart
+++ b/packages/flutter/test/material/dialog_test.dart
@@ -344,6 +344,37 @@
});
+ testWidgets('Barrier color', (WidgetTester tester) async {
+ await tester.pumpWidget(
+ const MaterialApp(
+ home: Center(child: Text('Test')),
+ ),
+ );
+ final BuildContext context = tester.element(find.text('Test'));
+
+ // Test default barrier color
+ showDialog<void>(
+ context: context,
+ builder: (BuildContext context) {
+ return const Text('Dialog');
+ },
+ );
+ await tester.pumpAndSettle();
+ expect(tester.widget<ModalBarrier>(find.byType(ModalBarrier).last).color, Colors.black54);
+
+ // Dismiss it and test a custom barrier color
+ await tester.tapAt(const Offset(10.0, 10.0));
+ showDialog<void>(
+ context: context,
+ builder: (BuildContext context) {
+ return const Text('Dialog');
+ },
+ barrierColor: Colors.pink,
+ );
+ await tester.pumpAndSettle();
+ expect(tester.widget<ModalBarrier>(find.byType(ModalBarrier).last).color, Colors.pink);
+ });
+
testWidgets('Dialog hides underlying semantics tree', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester);
const String buttonText = 'A button covered by dialog overlay';
@@ -1020,6 +1051,47 @@
await tester.pump();
});
+ testWidgets('showDialog safe area', (WidgetTester tester) async {
+ await tester.pumpWidget(
+ MaterialApp(
+ builder: (BuildContext context, Widget child) {
+ return MediaQuery(
+ // Set up the safe area to be 20 pixels in from each side
+ data: const MediaQueryData(padding: EdgeInsets.all(20.0)),
+ child: child,
+ );
+ },
+ home: const Center(child: Text('Test')),
+ ),
+ );
+ final BuildContext context = tester.element(find.text('Test'));
+
+ // By default it should honor the safe area
+ showDialog<void>(
+ context: context,
+ builder: (BuildContext context) {
+ return const Placeholder();
+ },
+ );
+ await tester.pumpAndSettle();
+ expect(tester.getTopLeft(find.byType(Placeholder)), const Offset(20.0, 20.0));
+ expect(tester.getBottomRight(find.byType(Placeholder)), const Offset(780.0, 580.0));
+
+ // Dismiss it and test with useSafeArea off
+ await tester.tapAt(const Offset(10.0, 10.0));
+ showDialog<void>(
+ context: context,
+ builder: (BuildContext context) {
+ return const Placeholder();
+ },
+ useSafeArea: false,
+ );
+ await tester.pumpAndSettle();
+ // Should take up the whole screen
+ expect(tester.getTopLeft(find.byType(Placeholder)), const Offset(0.0, 0.0));
+ expect(tester.getBottomRight(find.byType(Placeholder)), const Offset(800.0, 600.0));
+ });
+
testWidgets('showDialog uses root navigator by default', (WidgetTester tester) async {
final DialogObserver rootObserver = DialogObserver();
final DialogObserver nestedObserver = DialogObserver();