Allow for custom alignment for Dialogs (#88984)
This commit is contained in:
parent
bce366203a
commit
dd9169ec71
@ -47,6 +47,7 @@ class Dialog extends StatelessWidget {
|
||||
this.insetPadding = _defaultInsetPadding,
|
||||
this.clipBehavior = Clip.none,
|
||||
this.shape,
|
||||
this.alignment,
|
||||
this.child,
|
||||
}) : assert(clipBehavior != null),
|
||||
super(key: key);
|
||||
@ -114,6 +115,14 @@ class Dialog extends StatelessWidget {
|
||||
/// {@endtemplate}
|
||||
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.
|
||||
///
|
||||
/// {@macro flutter.widgets.ProxyWidget.child}
|
||||
@ -137,7 +146,8 @@ class Dialog extends StatelessWidget {
|
||||
removeRight: true,
|
||||
removeBottom: true,
|
||||
context: context,
|
||||
child: Center(
|
||||
child: Align(
|
||||
alignment: alignment ?? dialogTheme.alignment ?? Alignment.center,
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(minWidth: 280.0),
|
||||
child: Material(
|
||||
@ -260,6 +270,7 @@ class AlertDialog extends StatelessWidget {
|
||||
this.insetPadding = _defaultInsetPadding,
|
||||
this.clipBehavior = Clip.none,
|
||||
this.shape,
|
||||
this.alignment,
|
||||
this.scrollable = false,
|
||||
}) : assert(contentPadding != null),
|
||||
assert(clipBehavior != null),
|
||||
@ -437,6 +448,9 @@ class AlertDialog extends StatelessWidget {
|
||||
/// {@macro flutter.material.dialog.shape}
|
||||
final ShapeBorder? shape;
|
||||
|
||||
/// {@macro flutter.material.dialog.shape}
|
||||
final AlignmentGeometry? alignment;
|
||||
|
||||
/// Determines whether the [title] and [content] widgets are wrapped in a
|
||||
/// scrollable.
|
||||
///
|
||||
@ -577,6 +591,7 @@ class AlertDialog extends StatelessWidget {
|
||||
insetPadding: insetPadding,
|
||||
clipBehavior: clipBehavior,
|
||||
shape: shape,
|
||||
alignment: alignment,
|
||||
child: dialogChild,
|
||||
);
|
||||
}
|
||||
@ -742,6 +757,7 @@ class SimpleDialog extends StatelessWidget {
|
||||
this.insetPadding = _defaultInsetPadding,
|
||||
this.clipBehavior = Clip.none,
|
||||
this.shape,
|
||||
this.alignment,
|
||||
}) : assert(titlePadding != null),
|
||||
assert(contentPadding != null),
|
||||
super(key: key);
|
||||
@ -818,6 +834,9 @@ class SimpleDialog extends StatelessWidget {
|
||||
/// {@macro flutter.material.dialog.shape}
|
||||
final ShapeBorder? shape;
|
||||
|
||||
/// {@macro flutter.material.dialog.shape}
|
||||
final AlignmentGeometry? alignment;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
assert(debugCheckHasMaterialLocalizations(context));
|
||||
@ -908,6 +927,7 @@ class SimpleDialog extends StatelessWidget {
|
||||
insetPadding: insetPadding,
|
||||
clipBehavior: clipBehavior,
|
||||
shape: shape,
|
||||
alignment: alignment,
|
||||
child: dialogChild,
|
||||
);
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ class DialogTheme with Diagnosticable {
|
||||
this.backgroundColor,
|
||||
this.elevation,
|
||||
this.shape,
|
||||
this.alignment,
|
||||
this.titleTextStyle,
|
||||
this.contentTextStyle,
|
||||
});
|
||||
@ -52,6 +53,11 @@ class DialogTheme with Diagnosticable {
|
||||
/// Default value for [Dialog.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.
|
||||
///
|
||||
/// If null, defaults to [TextTheme.headline6] of [ThemeData.textTheme].
|
||||
@ -68,6 +74,7 @@ class DialogTheme with Diagnosticable {
|
||||
Color? backgroundColor,
|
||||
double? elevation,
|
||||
ShapeBorder? shape,
|
||||
AlignmentGeometry? alignment,
|
||||
TextStyle? titleTextStyle,
|
||||
TextStyle? contentTextStyle,
|
||||
}) {
|
||||
@ -75,6 +82,7 @@ class DialogTheme with Diagnosticable {
|
||||
backgroundColor: backgroundColor ?? this.backgroundColor,
|
||||
elevation: elevation ?? this.elevation,
|
||||
shape: shape ?? this.shape,
|
||||
alignment: alignment ?? this.alignment,
|
||||
titleTextStyle: titleTextStyle ?? this.titleTextStyle,
|
||||
contentTextStyle: contentTextStyle ?? this.contentTextStyle,
|
||||
);
|
||||
@ -96,6 +104,7 @@ class DialogTheme with Diagnosticable {
|
||||
backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t),
|
||||
elevation: lerpDouble(a?.elevation, b?.elevation, 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),
|
||||
contentTextStyle: TextStyle.lerp(a?.contentTextStyle, b?.contentTextStyle, t),
|
||||
);
|
||||
@ -114,6 +123,7 @@ class DialogTheme with Diagnosticable {
|
||||
&& other.backgroundColor == backgroundColor
|
||||
&& other.elevation == elevation
|
||||
&& other.shape == shape
|
||||
&& other.alignment == alignment
|
||||
&& other.titleTextStyle == titleTextStyle
|
||||
&& other.contentTextStyle == contentTextStyle;
|
||||
}
|
||||
@ -122,8 +132,9 @@ class DialogTheme with Diagnosticable {
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
properties.add(ColorProperty('backgroundColor', backgroundColor));
|
||||
properties.add(DiagnosticsProperty<ShapeBorder>('shape', shape, defaultValue: null));
|
||||
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>('contentTextStyle', contentTextStyle, defaultValue: null));
|
||||
}
|
||||
|
@ -113,6 +113,11 @@ void main() {
|
||||
expect(materialWidget.color, Colors.grey[800]);
|
||||
expect(materialWidget.shape, _defaultDialogShape);
|
||||
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 {
|
||||
@ -237,6 +242,23 @@ void main() {
|
||||
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 {
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
|
@ -48,6 +48,7 @@ void main() {
|
||||
backgroundColor: Color(0xff123456),
|
||||
elevation: 8.0,
|
||||
shape: null,
|
||||
alignment: Alignment.bottomLeft,
|
||||
titleTextStyle: TextStyle(color: Color(0xffffffff)),
|
||||
contentTextStyle: TextStyle(color: Color(0xff000000)),
|
||||
).debugFillProperties(builder);
|
||||
@ -57,6 +58,7 @@ void main() {
|
||||
expect(description, <String>[
|
||||
'backgroundColor: Color(0xff123456)',
|
||||
'elevation: 8.0',
|
||||
'alignment: Alignment.bottomLeft',
|
||||
'titleTextStyle: TextStyle(inherit: true, color: Color(0xffffffff))',
|
||||
'contentTextStyle: TextStyle(inherit: true, color: Color(0xff000000))',
|
||||
]);
|
||||
@ -115,6 +117,47 @@ void main() {
|
||||
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 {
|
||||
const RoundedRectangleBorder customBorder =
|
||||
RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0)));
|
||||
|
Loading…
x
Reference in New Issue
Block a user