Unverified Commit dd9169ec authored by Rami's avatar Rami Committed by GitHub

Allow for custom alignment for Dialogs (#88984)

parent bce36620
...@@ -47,6 +47,7 @@ class Dialog extends StatelessWidget { ...@@ -47,6 +47,7 @@ class Dialog extends StatelessWidget {
this.insetPadding = _defaultInsetPadding, this.insetPadding = _defaultInsetPadding,
this.clipBehavior = Clip.none, this.clipBehavior = Clip.none,
this.shape, this.shape,
this.alignment,
this.child, this.child,
}) : assert(clipBehavior != null), }) : assert(clipBehavior != null),
super(key: key); super(key: key);
...@@ -114,6 +115,14 @@ class Dialog extends StatelessWidget { ...@@ -114,6 +115,14 @@ class Dialog extends StatelessWidget {
/// {@endtemplate} /// {@endtemplate}
final ShapeBorder? shape; final ShapeBorder? shape;
/// {@template flutter.material.dialog.alignment}
/// How to align the [Dialog].
///
/// If null, then [DialogTheme.alignment] is used. If that is also null, the
/// default is [Alignment.center].
/// {@endtemplate}
final AlignmentGeometry? alignment;
/// The widget below this widget in the tree. /// The widget below this widget in the tree.
/// ///
/// {@macro flutter.widgets.ProxyWidget.child} /// {@macro flutter.widgets.ProxyWidget.child}
...@@ -137,7 +146,8 @@ class Dialog extends StatelessWidget { ...@@ -137,7 +146,8 @@ class Dialog extends StatelessWidget {
removeRight: true, removeRight: true,
removeBottom: true, removeBottom: true,
context: context, context: context,
child: Center( child: Align(
alignment: alignment ?? dialogTheme.alignment ?? Alignment.center,
child: ConstrainedBox( child: ConstrainedBox(
constraints: const BoxConstraints(minWidth: 280.0), constraints: const BoxConstraints(minWidth: 280.0),
child: Material( child: Material(
...@@ -260,6 +270,7 @@ class AlertDialog extends StatelessWidget { ...@@ -260,6 +270,7 @@ class AlertDialog extends StatelessWidget {
this.insetPadding = _defaultInsetPadding, this.insetPadding = _defaultInsetPadding,
this.clipBehavior = Clip.none, this.clipBehavior = Clip.none,
this.shape, this.shape,
this.alignment,
this.scrollable = false, this.scrollable = false,
}) : assert(contentPadding != null), }) : assert(contentPadding != null),
assert(clipBehavior != null), assert(clipBehavior != null),
...@@ -437,6 +448,9 @@ class AlertDialog extends StatelessWidget { ...@@ -437,6 +448,9 @@ class AlertDialog extends StatelessWidget {
/// {@macro flutter.material.dialog.shape} /// {@macro flutter.material.dialog.shape}
final ShapeBorder? shape; final ShapeBorder? shape;
/// {@macro flutter.material.dialog.shape}
final AlignmentGeometry? alignment;
/// Determines whether the [title] and [content] widgets are wrapped in a /// Determines whether the [title] and [content] widgets are wrapped in a
/// scrollable. /// scrollable.
/// ///
...@@ -577,6 +591,7 @@ class AlertDialog extends StatelessWidget { ...@@ -577,6 +591,7 @@ class AlertDialog extends StatelessWidget {
insetPadding: insetPadding, insetPadding: insetPadding,
clipBehavior: clipBehavior, clipBehavior: clipBehavior,
shape: shape, shape: shape,
alignment: alignment,
child: dialogChild, child: dialogChild,
); );
} }
...@@ -742,6 +757,7 @@ class SimpleDialog extends StatelessWidget { ...@@ -742,6 +757,7 @@ class SimpleDialog extends StatelessWidget {
this.insetPadding = _defaultInsetPadding, this.insetPadding = _defaultInsetPadding,
this.clipBehavior = Clip.none, this.clipBehavior = Clip.none,
this.shape, this.shape,
this.alignment,
}) : assert(titlePadding != null), }) : assert(titlePadding != null),
assert(contentPadding != null), assert(contentPadding != null),
super(key: key); super(key: key);
...@@ -818,6 +834,9 @@ class SimpleDialog extends StatelessWidget { ...@@ -818,6 +834,9 @@ class SimpleDialog extends StatelessWidget {
/// {@macro flutter.material.dialog.shape} /// {@macro flutter.material.dialog.shape}
final ShapeBorder? shape; final ShapeBorder? shape;
/// {@macro flutter.material.dialog.shape}
final AlignmentGeometry? alignment;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
assert(debugCheckHasMaterialLocalizations(context)); assert(debugCheckHasMaterialLocalizations(context));
...@@ -908,6 +927,7 @@ class SimpleDialog extends StatelessWidget { ...@@ -908,6 +927,7 @@ class SimpleDialog extends StatelessWidget {
insetPadding: insetPadding, insetPadding: insetPadding,
clipBehavior: clipBehavior, clipBehavior: clipBehavior,
shape: shape, shape: shape,
alignment: alignment,
child: dialogChild, child: dialogChild,
); );
} }
......
...@@ -34,6 +34,7 @@ class DialogTheme with Diagnosticable { ...@@ -34,6 +34,7 @@ class DialogTheme with Diagnosticable {
this.backgroundColor, this.backgroundColor,
this.elevation, this.elevation,
this.shape, this.shape,
this.alignment,
this.titleTextStyle, this.titleTextStyle,
this.contentTextStyle, this.contentTextStyle,
}); });
...@@ -52,6 +53,11 @@ class DialogTheme with Diagnosticable { ...@@ -52,6 +53,11 @@ class DialogTheme with Diagnosticable {
/// Default value for [Dialog.shape]. /// Default value for [Dialog.shape].
final ShapeBorder? shape; final ShapeBorder? shape;
/// Default value for [Dialog.alignment].
///
/// If null, the [Dialog] alignment defaults to [Alignment.center].
final AlignmentGeometry? alignment;
/// Used to configure the [DefaultTextStyle] for the [AlertDialog.title] widget. /// Used to configure the [DefaultTextStyle] for the [AlertDialog.title] widget.
/// ///
/// If null, defaults to [TextTheme.headline6] of [ThemeData.textTheme]. /// If null, defaults to [TextTheme.headline6] of [ThemeData.textTheme].
...@@ -68,6 +74,7 @@ class DialogTheme with Diagnosticable { ...@@ -68,6 +74,7 @@ class DialogTheme with Diagnosticable {
Color? backgroundColor, Color? backgroundColor,
double? elevation, double? elevation,
ShapeBorder? shape, ShapeBorder? shape,
AlignmentGeometry? alignment,
TextStyle? titleTextStyle, TextStyle? titleTextStyle,
TextStyle? contentTextStyle, TextStyle? contentTextStyle,
}) { }) {
...@@ -75,6 +82,7 @@ class DialogTheme with Diagnosticable { ...@@ -75,6 +82,7 @@ class DialogTheme with Diagnosticable {
backgroundColor: backgroundColor ?? this.backgroundColor, backgroundColor: backgroundColor ?? this.backgroundColor,
elevation: elevation ?? this.elevation, elevation: elevation ?? this.elevation,
shape: shape ?? this.shape, shape: shape ?? this.shape,
alignment: alignment ?? this.alignment,
titleTextStyle: titleTextStyle ?? this.titleTextStyle, titleTextStyle: titleTextStyle ?? this.titleTextStyle,
contentTextStyle: contentTextStyle ?? this.contentTextStyle, contentTextStyle: contentTextStyle ?? this.contentTextStyle,
); );
...@@ -96,6 +104,7 @@ class DialogTheme with Diagnosticable { ...@@ -96,6 +104,7 @@ class DialogTheme with Diagnosticable {
backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t), backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t),
elevation: lerpDouble(a?.elevation, b?.elevation, t), elevation: lerpDouble(a?.elevation, b?.elevation, t),
shape: ShapeBorder.lerp(a?.shape, b?.shape, t), shape: ShapeBorder.lerp(a?.shape, b?.shape, t),
alignment: AlignmentGeometry.lerp(a?.alignment, b?.alignment, t),
titleTextStyle: TextStyle.lerp(a?.titleTextStyle, b?.titleTextStyle, t), titleTextStyle: TextStyle.lerp(a?.titleTextStyle, b?.titleTextStyle, t),
contentTextStyle: TextStyle.lerp(a?.contentTextStyle, b?.contentTextStyle, t), contentTextStyle: TextStyle.lerp(a?.contentTextStyle, b?.contentTextStyle, t),
); );
...@@ -114,6 +123,7 @@ class DialogTheme with Diagnosticable { ...@@ -114,6 +123,7 @@ class DialogTheme with Diagnosticable {
&& other.backgroundColor == backgroundColor && other.backgroundColor == backgroundColor
&& other.elevation == elevation && other.elevation == elevation
&& other.shape == shape && other.shape == shape
&& other.alignment == alignment
&& other.titleTextStyle == titleTextStyle && other.titleTextStyle == titleTextStyle
&& other.contentTextStyle == contentTextStyle; && other.contentTextStyle == contentTextStyle;
} }
...@@ -122,8 +132,9 @@ class DialogTheme with Diagnosticable { ...@@ -122,8 +132,9 @@ class DialogTheme with Diagnosticable {
void debugFillProperties(DiagnosticPropertiesBuilder properties) { void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties); super.debugFillProperties(properties);
properties.add(ColorProperty('backgroundColor', backgroundColor)); properties.add(ColorProperty('backgroundColor', backgroundColor));
properties.add(DiagnosticsProperty<ShapeBorder>('shape', shape, defaultValue: null));
properties.add(DoubleProperty('elevation', elevation)); properties.add(DoubleProperty('elevation', elevation));
properties.add(DiagnosticsProperty<ShapeBorder>('shape', shape, defaultValue: null));
properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment, defaultValue: null));
properties.add(DiagnosticsProperty<TextStyle>('titleTextStyle', titleTextStyle, defaultValue: null)); properties.add(DiagnosticsProperty<TextStyle>('titleTextStyle', titleTextStyle, defaultValue: null));
properties.add(DiagnosticsProperty<TextStyle>('contentTextStyle', contentTextStyle, defaultValue: null)); properties.add(DiagnosticsProperty<TextStyle>('contentTextStyle', contentTextStyle, defaultValue: null));
} }
......
...@@ -113,6 +113,11 @@ void main() { ...@@ -113,6 +113,11 @@ void main() {
expect(materialWidget.color, Colors.grey[800]); expect(materialWidget.color, Colors.grey[800]);
expect(materialWidget.shape, _defaultDialogShape); expect(materialWidget.shape, _defaultDialogShape);
expect(materialWidget.elevation, 24.0); expect(materialWidget.elevation, 24.0);
final Offset bottomLeft = tester.getBottomLeft(
find.descendant(of: find.byType(Dialog), matching: find.byType(Material)),
);
expect(bottomLeft.dy, 360.0);
}); });
testWidgets('Custom dialog elevation', (WidgetTester tester) async { testWidgets('Custom dialog elevation', (WidgetTester tester) async {
...@@ -237,6 +242,23 @@ void main() { ...@@ -237,6 +242,23 @@ void main() {
expect(materialWidget.shape, customBorder); expect(materialWidget.shape, customBorder);
}); });
testWidgets('Custom dialog alignment', (WidgetTester tester) async {
const AlertDialog dialog = AlertDialog(
actions: <Widget>[ ],
alignment: Alignment.bottomLeft,
);
await tester.pumpWidget(_buildAppWithDialog(dialog));
await tester.tap(find.text('X'));
await tester.pumpAndSettle();
final Offset bottomLeft = tester.getBottomLeft(
find.descendant(of: find.byType(Dialog), matching: find.byType(Material)),
);
expect(bottomLeft.dx, 40.0);
expect(bottomLeft.dy, 576.0);
});
testWidgets('Simple dialog control test', (WidgetTester tester) async { testWidgets('Simple dialog control test', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
const MaterialApp( const MaterialApp(
......
...@@ -48,6 +48,7 @@ void main() { ...@@ -48,6 +48,7 @@ void main() {
backgroundColor: Color(0xff123456), backgroundColor: Color(0xff123456),
elevation: 8.0, elevation: 8.0,
shape: null, shape: null,
alignment: Alignment.bottomLeft,
titleTextStyle: TextStyle(color: Color(0xffffffff)), titleTextStyle: TextStyle(color: Color(0xffffffff)),
contentTextStyle: TextStyle(color: Color(0xff000000)), contentTextStyle: TextStyle(color: Color(0xff000000)),
).debugFillProperties(builder); ).debugFillProperties(builder);
...@@ -57,6 +58,7 @@ void main() { ...@@ -57,6 +58,7 @@ void main() {
expect(description, <String>[ expect(description, <String>[
'backgroundColor: Color(0xff123456)', 'backgroundColor: Color(0xff123456)',
'elevation: 8.0', 'elevation: 8.0',
'alignment: Alignment.bottomLeft',
'titleTextStyle: TextStyle(inherit: true, color: Color(0xffffffff))', 'titleTextStyle: TextStyle(inherit: true, color: Color(0xffffffff))',
'contentTextStyle: TextStyle(inherit: true, color: Color(0xff000000))', 'contentTextStyle: TextStyle(inherit: true, color: Color(0xff000000))',
]); ]);
...@@ -115,6 +117,47 @@ void main() { ...@@ -115,6 +117,47 @@ void main() {
expect(materialWidget.shape, customBorder); expect(materialWidget.shape, customBorder);
}); });
testWidgets('Custom dialog alignment', (WidgetTester tester) async {
const AlertDialog dialog = AlertDialog(
title: Text('Title'),
actions: <Widget>[ ],
);
final ThemeData theme = ThemeData(dialogTheme: const DialogTheme(alignment: Alignment.bottomLeft));
await tester.pumpWidget(
_appWithDialog(tester, dialog, theme: theme),
);
await tester.tap(find.text('X'));
await tester.pumpAndSettle();
final Offset bottomLeft = tester.getBottomLeft(
find.descendant(of: find.byType(Dialog), matching: find.byType(Material)),
);
expect(bottomLeft.dx, 40.0);
expect(bottomLeft.dy, 576.0);
});
testWidgets('Dialog alignment takes priority over theme', (WidgetTester tester) async {
const AlertDialog dialog = AlertDialog(
title: Text('Title'),
actions: <Widget>[ ],
alignment: Alignment.topRight,
);
final ThemeData theme = ThemeData(dialogTheme: const DialogTheme(alignment: Alignment.bottomLeft));
await tester.pumpWidget(
_appWithDialog(tester, dialog, theme: theme),
);
await tester.tap(find.text('X'));
await tester.pumpAndSettle();
final Offset bottomLeft = tester.getBottomLeft(
find.descendant(of: find.byType(Dialog), matching: find.byType(Material)),
);
expect(bottomLeft.dx, 480.0);
expect(bottomLeft.dy, 104.0);
});
testWidgets('Custom dialog shape matches golden', (WidgetTester tester) async { testWidgets('Custom dialog shape matches golden', (WidgetTester tester) async {
const RoundedRectangleBorder customBorder = const RoundedRectangleBorder customBorder =
RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))); RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0)));
......
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