Skip to content

Commit 8ec5001

Browse files
authored
Provide default constraints for M3 dialogs (#120082)
This PR constrains M3 dialogs to 560dp max width and height. This is not a breaking change per the breaking change policy. Part of flutter/flutter#118619 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [Features we expect every widget to implement]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat
1 parent c2022aa commit 8ec5001

File tree

3 files changed

+63
-31
lines changed

3 files changed

+63
-31
lines changed

packages/flutter/lib/src/material/dialog.dart

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import 'theme_data.dart';
2424

2525
const EdgeInsets _defaultInsetPadding = EdgeInsets.symmetric(horizontal: 40.0, vertical: 24.0);
2626

27+
const BoxConstraints _dialogConstraints = BoxConstraints(minWidth: 280.0, maxWidth: 560.0, maxHeight: 560.0);
28+
2729
/// A Material Design dialog.
2830
///
2931
/// This dialog widget does not have any opinion about the contents of the
@@ -232,7 +234,7 @@ class Dialog extends StatelessWidget {
232234
dialogChild = Align(
233235
alignment: alignment ?? dialogTheme.alignment ?? defaults.alignment!,
234236
child: ConstrainedBox(
235-
constraints: const BoxConstraints(minWidth: 280.0),
237+
constraints: _constraintsScaleFactor(MediaQuery.of(context).textScaleFactor, theme.useMaterial3),
236238
child: Material(
237239
color: backgroundColor ?? dialogTheme.backgroundColor ?? Theme.of(context).dialogBackgroundColor,
238240
elevation: elevation ?? dialogTheme.elevation ?? defaults.elevation!,
@@ -1261,7 +1263,7 @@ class SimpleDialog extends StatelessWidget {
12611263
Widget dialogChild = IntrinsicWidth(
12621264
stepWidth: 56.0,
12631265
child: ConstrainedBox(
1264-
constraints: const BoxConstraints(minWidth: 280.0),
1266+
constraints: _constraintsScaleFactor(MediaQuery.of(context).textScaleFactor, theme.useMaterial3),
12651267
child: Column(
12661268
mainAxisSize: MainAxisSize.min,
12671269
crossAxisAlignment: CrossAxisAlignment.stretch,
@@ -1587,6 +1589,17 @@ double _paddingScaleFactor(double textScaleFactor) {
15871589
return lerpDouble(1.0, 1.0 / 3.0, clampedTextScaleFactor - 1.0)!;
15881590
}
15891591

1592+
BoxConstraints _constraintsScaleFactor(double textScaleFactor, bool useMaterial3) {
1593+
if (!useMaterial3) {
1594+
return const BoxConstraints(minWidth: 280.0);
1595+
} else {
1596+
return textScaleFactor == 1.0
1597+
? _dialogConstraints
1598+
// Scale the max height of the dialog by the text scale factor to aid in readability.
1599+
: _dialogConstraints.copyWith(maxHeight: _dialogConstraints.maxHeight * textScaleFactor);
1600+
}
1601+
}
1602+
15901603
// Hand coded defaults based on Material Design 2.
15911604
class _DialogDefaultsM2 extends DialogTheme {
15921605
_DialogDefaultsM2(this.context)

packages/flutter/test/material/dialog_test.dart

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import 'dart:ui';
66

77
import 'package:flutter/cupertino.dart';
8+
import 'package:flutter/foundation.dart';
89
import 'package:flutter/material.dart';
910
import 'package:flutter/rendering.dart';
1011
import 'package:flutter/services.dart';
@@ -61,6 +62,16 @@ Finder _findButtonBar() {
6162
return find.ancestor(of: find.byType(OverflowBar), matching: find.byType(Padding)).first;
6263
}
6364

65+
// In the case of [AlertDialog], it takes up the entire screen, since it also
66+
// contains the scrim. The first [Material] child of [AlertDialog] is the actual
67+
// dialog itself.
68+
Size _getDialogSize(WidgetTester tester) => tester.getSize(
69+
find.descendant(
70+
of: find.byType(AlertDialog),
71+
matching: find.byType(Material),
72+
).first,
73+
);
74+
6475
const ShapeBorder _defaultM2DialogShape = RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0)));
6576
final ShapeBorder _defaultM3DialogShape = RoundedRectangleBorder(borderRadius: BorderRadius.circular(28.0));
6677

@@ -144,6 +155,8 @@ void main() {
144155
expect(material3Widget.color, material3Theme.colorScheme.surface);
145156
expect(material3Widget.shape, _defaultM3DialogShape);
146157
expect(material3Widget.elevation, 6.0);
158+
// For some unknown reason, one pixel wider on web (HTML).
159+
expect(_getDialogSize(tester), Size(280.0, isBrowser && !isCanvasKit ? 141.0 : 140.0));
147160
});
148161

149162
testWidgets('Dialog.fullscreen Defaults', (WidgetTester tester) async {
@@ -337,6 +350,26 @@ void main() {
337350
expect(bottomLeft.dy, 576.0);
338351
});
339352

353+
testWidgets('Dialog respects constraints with large content on large screens', (WidgetTester tester) async {
354+
const AlertDialog dialog = AlertDialog(
355+
actions: <Widget>[ ],
356+
content: SizedBox(
357+
width: 1000.0,
358+
height: 1000.0,
359+
),
360+
);
361+
362+
tester.view.physicalSize = const Size(2000, 2000);
363+
addTearDown(tester.view.resetPhysicalSize);
364+
365+
await tester.pumpWidget(_buildAppWithDialog(dialog, theme: material3Theme));
366+
367+
await tester.tap(find.text('X'));
368+
await tester.pumpAndSettle();
369+
370+
expect(_getDialogSize(tester), const Size(560.0, 560.0));
371+
});
372+
340373
testWidgets('Simple dialog control test', (WidgetTester tester) async {
341374
await tester.pumpWidget(
342375
const MaterialApp(
@@ -593,15 +626,8 @@ void main() {
593626
await tester.tap(find.text('X'));
594627
await tester.pumpAndSettle();
595628

596-
// The [AlertDialog] is the entire screen, since it also contains the scrim.
597-
// The first [Material] child of [AlertDialog] is the actual dialog
598-
// itself.
599-
final Size dialogSize = tester.getSize(
600-
find.descendant(
601-
of: find.byType(AlertDialog),
602-
matching: find.byType(Material),
603-
).first,
604-
);
629+
630+
final Size dialogSize = _getDialogSize(tester);
605631
final Size actionsSize = tester.getSize(_findButtonBar());
606632

607633
expect(actionsSize.width, dialogSize.width);
@@ -629,15 +655,7 @@ void main() {
629655
await tester.tap(find.text('X'));
630656
await tester.pumpAndSettle();
631657

632-
// The [AlertDialog] is the entire screen, since it also contains the scrim.
633-
// The first [Material] child of [AlertDialog] is the actual dialog
634-
// itself.
635-
final Size dialogSize = tester.getSize(
636-
find.descendant(
637-
of: find.byType(AlertDialog),
638-
matching: find.byType(Material),
639-
).first,
640-
);
658+
final Size dialogSize = _getDialogSize(tester);
641659
final Size actionsSize = tester.getSize(find.byType(OverflowBar));
642660

643661
expect(actionsSize.width, dialogSize.width - (30.0 * 2));

packages/flutter/test/material/time_picker_test.dart

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
@TestOn('!chrome')
66
library;
77

8+
import 'dart:math';
89
import 'dart:ui';
910

1011
import 'package:flutter/material.dart';
@@ -426,7 +427,7 @@ void main() {
426427
tester.view.devicePixelRatio = 1;
427428
await mediaQueryBoilerplate(tester, materialType: materialType);
428429

429-
width = timePickerPortraitSize.width + padding.horizontal;
430+
width = min(timePickerPortraitSize.width + padding.horizontal, 560); // width is limited to 560
430431
height = timePickerPortraitSize.height + padding.vertical;
431432
expect(
432433
tester.getSize(find.byWidget(getMaterialFromDialog(tester))),
@@ -445,7 +446,7 @@ void main() {
445446
materialType: materialType,
446447
);
447448

448-
width = timePickerLandscapeSize.width + padding.horizontal;
449+
width = min(timePickerLandscapeSize.width + padding.horizontal, 560); // width is limited to 560
449450
height = timePickerLandscapeSize.height + padding.vertical;
450451
expect(
451452
tester.getSize(find.byWidget(getMaterialFromDialog(tester))),
@@ -749,10 +750,10 @@ void main() {
749750
expect(tester.getBottomLeft(find.text(okString)).dx, 616);
750751
expect(tester.getBottomRight(find.text(cancelString)).dx, 582);
751752
case MaterialType.material3:
752-
expect(tester.getTopLeft(find.text(selectTimeString)), equals(const Offset(138, 129)));
753-
expect(tester.getBottomRight(find.text(selectTimeString)), equals(const Offset(292.0, 143.0)));
754-
expect(tester.getBottomLeft(find.text(okString)).dx, 616);
755-
expect(tester.getBottomRight(find.text(cancelString)).dx, 578);
753+
expect(tester.getTopLeft(find.text(selectTimeString)), equals(const Offset(144, 129)));
754+
expect(tester.getBottomRight(find.text(selectTimeString)), equals(const Offset(298.0, 143.0)));
755+
expect(tester.getBottomLeft(find.text(okString)).dx, 610);
756+
expect(tester.getBottomRight(find.text(cancelString)).dx, 572);
756757
}
757758

758759
await tester.tap(find.text(okString));
@@ -770,11 +771,11 @@ void main() {
770771
expect(tester.getBottomRight(find.text(okString)).dx, 184);
771772
expect(tester.getBottomLeft(find.text(cancelString)).dx, 218);
772773
case MaterialType.material3:
773-
expect(tester.getTopLeft(find.text(selectTimeString)), equals(const Offset(508, 129)));
774-
expect(tester.getBottomRight(find.text(selectTimeString)), equals(const Offset(662, 143)));
775-
expect(tester.getBottomLeft(find.text(okString)).dx, 156);
776-
expect(tester.getBottomRight(find.text(okString)).dx, 184);
777-
expect(tester.getBottomLeft(find.text(cancelString)).dx, 222);
774+
expect(tester.getTopLeft(find.text(selectTimeString)), equals(const Offset(502, 129)));
775+
expect(tester.getBottomRight(find.text(selectTimeString)), equals(const Offset(656, 143)));
776+
expect(tester.getBottomLeft(find.text(okString)).dx, 162);
777+
expect(tester.getBottomRight(find.text(okString)).dx, 190);
778+
expect(tester.getBottomLeft(find.text(cancelString)).dx, 228);
778779
}
779780

780781
await tester.tap(find.text(okString));

0 commit comments

Comments
 (0)