Unverified Commit 457985f2 authored by Hans Muller's avatar Hans Muller Committed by GitHub

Added ButtonStyle.maximumSize (#80087)

parent 1a36c184
......@@ -109,6 +109,7 @@ class ButtonStyle with Diagnosticable {
this.padding,
this.minimumSize,
this.fixedSize,
this.maximumSize,
this.side,
this.shape,
this.mouseCursor,
......@@ -159,18 +160,29 @@ class ButtonStyle with Diagnosticable {
///
/// The size of the rectangle the button lies within may be larger
/// per [tapTargetSize].
///
/// This value must be less than or equal to [maximumSize].
final MaterialStateProperty<Size?>? minimumSize;
/// The button's size.
///
/// This size is still constrained by the style's [minimumSize]. Fixed
/// size dimensions whose value is [double.infinity] are ignored.
/// This size is still constrained by the style's [minimumSize]
/// and [maximumSize]. Fixed size dimensions whose value is
/// [double.infinity] are ignored.
///
/// To specify buttons with a fixed width and the default height use
/// `fixedSize: Size.fromWidth(320)`. Similarly, to specify a fixed
/// height and the default width use `fixedSize: Size.fromHeight(100)`.
final MaterialStateProperty<Size?>? fixedSize;
/// The maximum size of the button itself.
///
/// A [Size.infinite] or null value for this property means that
/// the button's maximum size is not constrained.
///
/// This value must be greater than or equal to [minimumSize].
final MaterialStateProperty<Size?>? maximumSize;
/// The color and weight of the button's outline.
///
/// This value is combined with [shape] to create a shape decorated
......@@ -259,6 +271,7 @@ class ButtonStyle with Diagnosticable {
MaterialStateProperty<EdgeInsetsGeometry?>? padding,
MaterialStateProperty<Size?>? minimumSize,
MaterialStateProperty<Size?>? fixedSize,
MaterialStateProperty<Size?>? maximumSize,
MaterialStateProperty<BorderSide?>? side,
MaterialStateProperty<OutlinedBorder?>? shape,
MaterialStateProperty<MouseCursor?>? mouseCursor,
......@@ -279,6 +292,7 @@ class ButtonStyle with Diagnosticable {
padding: padding ?? this.padding,
minimumSize: minimumSize ?? this.minimumSize,
fixedSize: fixedSize ?? this.fixedSize,
maximumSize: maximumSize ?? this.maximumSize,
side: side ?? this.side,
shape: shape ?? this.shape,
mouseCursor: mouseCursor ?? this.mouseCursor,
......@@ -309,6 +323,7 @@ class ButtonStyle with Diagnosticable {
padding: padding ?? style.padding,
minimumSize: minimumSize ?? style.minimumSize,
fixedSize: fixedSize ?? style.fixedSize,
maximumSize: maximumSize ?? style.maximumSize,
side: side ?? style.side,
shape: shape ?? style.shape,
mouseCursor: mouseCursor ?? style.mouseCursor,
......@@ -333,6 +348,7 @@ class ButtonStyle with Diagnosticable {
padding,
minimumSize,
fixedSize,
maximumSize,
side,
shape,
mouseCursor,
......@@ -361,6 +377,7 @@ class ButtonStyle with Diagnosticable {
&& other.padding == padding
&& other.minimumSize == minimumSize
&& other.fixedSize == fixedSize
&& other.maximumSize == maximumSize
&& other.side == side
&& other.shape == shape
&& other.mouseCursor == mouseCursor
......@@ -384,6 +401,7 @@ class ButtonStyle with Diagnosticable {
properties.add(DiagnosticsProperty<MaterialStateProperty<EdgeInsetsGeometry?>>('padding', padding, defaultValue: null));
properties.add(DiagnosticsProperty<MaterialStateProperty<Size?>>('minimumSize', minimumSize, defaultValue: null));
properties.add(DiagnosticsProperty<MaterialStateProperty<Size?>>('fixedSize', fixedSize, defaultValue: null));
properties.add(DiagnosticsProperty<MaterialStateProperty<Size?>>('maximumSize', maximumSize, defaultValue: null));
properties.add(DiagnosticsProperty<MaterialStateProperty<BorderSide?>>('side', side, defaultValue: null));
properties.add(DiagnosticsProperty<MaterialStateProperty<OutlinedBorder?>>('shape', shape, defaultValue: null));
properties.add(DiagnosticsProperty<MaterialStateProperty<MouseCursor?>>('mouseCursor', mouseCursor, defaultValue: null));
......@@ -409,6 +427,7 @@ class ButtonStyle with Diagnosticable {
padding: _lerpProperties<EdgeInsetsGeometry?>(a?.padding, b?.padding, t, EdgeInsetsGeometry.lerp),
minimumSize: _lerpProperties<Size?>(a?.minimumSize, b?.minimumSize, t, Size.lerp),
fixedSize: _lerpProperties<Size?>(a?.fixedSize, b?.fixedSize, t, Size.lerp),
maximumSize: _lerpProperties<Size?>(a?.maximumSize, b?.maximumSize, t, Size.lerp),
side: _lerpSides(a?.side, b?.side, t),
shape: _lerpShapes(a?.shape, b?.shape, t),
mouseCursor: t < 0.5 ? a?.mouseCursor : b?.mouseCursor,
......
......@@ -268,6 +268,7 @@ class _ButtonStyleState extends State<ButtonStyleButton> with TickerProviderStat
final EdgeInsetsGeometry? resolvedPadding = resolve<EdgeInsetsGeometry?>((ButtonStyle? style) => style?.padding);
final Size? resolvedMinimumSize = resolve<Size?>((ButtonStyle? style) => style?.minimumSize);
final Size? resolvedFixedSize = resolve<Size?>((ButtonStyle? style) => style?.fixedSize);
final Size? resolvedMaximumSize = resolve<Size?>((ButtonStyle? style) => style?.maximumSize);
final BorderSide? resolvedSide = resolve<BorderSide?>((ButtonStyle? style) => style?.side);
final OutlinedBorder? resolvedShape = resolve<OutlinedBorder?>((ButtonStyle? style) => style?.shape);
......@@ -291,6 +292,8 @@ class _ButtonStyleState extends State<ButtonStyleButton> with TickerProviderStat
BoxConstraints(
minWidth: resolvedMinimumSize!.width,
minHeight: resolvedMinimumSize.height,
maxWidth: resolvedMaximumSize!.width,
maxHeight: resolvedMaximumSize.height,
),
);
if (resolvedFixedSize != null) {
......
......@@ -174,6 +174,7 @@ class ElevatedButton extends ButtonStyleButton {
EdgeInsetsGeometry? padding,
Size? minimumSize,
Size? fixedSize,
Size? maximumSize,
BorderSide? side,
OutlinedBorder? shape,
MouseCursor? enabledMouseCursor,
......@@ -211,6 +212,7 @@ class ElevatedButton extends ButtonStyleButton {
padding: ButtonStyleButton.allOrNull<EdgeInsetsGeometry>(padding),
minimumSize: ButtonStyleButton.allOrNull<Size>(minimumSize),
fixedSize: ButtonStyleButton.allOrNull<Size>(fixedSize),
maximumSize: ButtonStyleButton.allOrNull<Size>(maximumSize),
side: ButtonStyleButton.allOrNull<BorderSide>(side),
shape: ButtonStyleButton.allOrNull<OutlinedBorder>(shape),
mouseCursor: mouseCursor,
......@@ -270,6 +272,7 @@ class ElevatedButton extends ButtonStyleButton {
/// * `3 < textScaleFactor` - horizontal(4)
/// * `minimumSize` - Size(64, 36)
/// * `fixedSize` - null
/// * `maximumSize` - Size.infinite
/// * `side` - null
/// * `shape` - RoundedRectangleBorder(borderRadius: BorderRadius.circular(4))
/// * `mouseCursor`
......@@ -315,6 +318,7 @@ class ElevatedButton extends ButtonStyleButton {
textStyle: theme.textTheme.button,
padding: scaledPadding,
minimumSize: const Size(64, 36),
maximumSize: Size.infinite,
side: null,
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4))),
enabledMouseCursor: SystemMouseCursors.click,
......
......@@ -149,6 +149,7 @@ class OutlinedButton extends ButtonStyleButton {
EdgeInsetsGeometry? padding,
Size? minimumSize,
Size? fixedSize,
Size? maximumSize,
BorderSide? side,
OutlinedBorder? shape,
MouseCursor? enabledMouseCursor,
......@@ -180,6 +181,7 @@ class OutlinedButton extends ButtonStyleButton {
padding: ButtonStyleButton.allOrNull<EdgeInsetsGeometry>(padding),
minimumSize: ButtonStyleButton.allOrNull<Size>(minimumSize),
fixedSize: ButtonStyleButton.allOrNull<Size>(fixedSize),
maximumSize: ButtonStyleButton.allOrNull<Size>(maximumSize),
side: ButtonStyleButton.allOrNull<BorderSide>(side),
shape: ButtonStyleButton.allOrNull<OutlinedBorder>(shape),
mouseCursor: mouseCursor,
......@@ -232,6 +234,7 @@ class OutlinedButton extends ButtonStyleButton {
/// * `3 < textScaleFactor` - horizontal(4)
/// * `minimumSize` - Size(64, 36)
/// * `fixedSize` - null
/// * `maximumSize` - Size.infinite
/// * `side` - BorderSide(width: 1, color: Theme.colorScheme.onSurface(0.12))
/// * `shape` - RoundedRectangleBorder(borderRadius: BorderRadius.circular(4))
/// * `mouseCursor`
......@@ -264,6 +267,7 @@ class OutlinedButton extends ButtonStyleButton {
textStyle: theme.textTheme.button,
padding: scaledPadding,
minimumSize: const Size(64, 36),
maximumSize: Size.infinite,
side: BorderSide(
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.12),
width: 1,
......
......@@ -203,6 +203,7 @@ class TextButton extends ButtonStyleButton {
EdgeInsetsGeometry? padding,
Size? minimumSize,
Size? fixedSize,
Size? maximumSize,
BorderSide? side,
OutlinedBorder? shape,
MouseCursor? enabledMouseCursor,
......@@ -234,6 +235,7 @@ class TextButton extends ButtonStyleButton {
padding: ButtonStyleButton.allOrNull<EdgeInsetsGeometry>(padding),
minimumSize: ButtonStyleButton.allOrNull<Size>(minimumSize),
fixedSize: ButtonStyleButton.allOrNull<Size>(fixedSize),
maximumSize: ButtonStyleButton.allOrNull<Size>(maximumSize),
side: ButtonStyleButton.allOrNull<BorderSide>(side),
shape: ButtonStyleButton.allOrNull<OutlinedBorder>(shape),
mouseCursor: mouseCursor,
......@@ -289,6 +291,7 @@ class TextButton extends ButtonStyleButton {
/// * `3 < textScaleFactor` - horizontal(4)
/// * `minimumSize` - Size(64, 36)
/// * `fixedSize` - null
/// * `maximumSize` - Size.infinite
/// * `side` - null
/// * `shape` - RoundedRectangleBorder(borderRadius: BorderRadius.circular(4))
/// * `mouseCursor`
......@@ -333,6 +336,7 @@ class TextButton extends ButtonStyleButton {
textStyle: theme.textTheme.button,
padding: scaledPadding,
minimumSize: const Size(64, 36),
maximumSize: Size.infinite,
side: null,
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4))),
enabledMouseCursor: SystemMouseCursors.click,
......
......@@ -24,6 +24,7 @@ void main() {
expect(style.padding, null);
expect(style.minimumSize, null);
expect(style.fixedSize, null);
expect(style.maximumSize, null);
expect(style.side, null);
expect(style.shape, null);
expect(style.mouseCursor, null);
......@@ -56,6 +57,7 @@ void main() {
padding: MaterialStateProperty.all<EdgeInsets>(const EdgeInsets.all(1.0)),
minimumSize: MaterialStateProperty.all<Size>(const Size(1.0, 2.0)),
side: MaterialStateProperty.all<BorderSide>(const BorderSide(width: 4.0, color: Color(0xfffffff4))),
maximumSize: MaterialStateProperty.all<Size>(const Size(100.0, 200.0)),
shape: MaterialStateProperty.all<OutlinedBorder>(const StadiumBorder()),
mouseCursor: MaterialStateProperty.all<MouseCursor>(SystemMouseCursors.forbidden),
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
......@@ -76,6 +78,7 @@ void main() {
'elevation: MaterialStateProperty.all(1.5)',
'padding: MaterialStateProperty.all(EdgeInsets.all(1.0))',
'minimumSize: MaterialStateProperty.all(Size(1.0, 2.0))',
'maximumSize: MaterialStateProperty.all(Size(100.0, 200.0))',
'side: MaterialStateProperty.all(BorderSide(Color(0xfffffff4), 4.0, BorderStyle.solid))',
'shape: MaterialStateProperty.all(StadiumBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none)))',
'mouseCursor: MaterialStateProperty.all(SystemMouseCursor(forbidden))',
......@@ -94,6 +97,7 @@ void main() {
final MaterialStateProperty<EdgeInsets> padding = MaterialStateProperty.all<EdgeInsets>(const EdgeInsets.all(1));
final MaterialStateProperty<Size> minimumSize = MaterialStateProperty.all<Size>(const Size(1, 2));
final MaterialStateProperty<Size> fixedSize = MaterialStateProperty.all<Size>(const Size(3, 4));
final MaterialStateProperty<Size> maximumSize = MaterialStateProperty.all<Size>(const Size(5, 6));
final MaterialStateProperty<BorderSide> side = MaterialStateProperty.all<BorderSide>(const BorderSide());
final MaterialStateProperty<OutlinedBorder> shape = MaterialStateProperty.all<OutlinedBorder>(const StadiumBorder());
final MaterialStateProperty<MouseCursor> mouseCursor = MaterialStateProperty.all<MouseCursor>(SystemMouseCursors.forbidden);
......@@ -111,6 +115,7 @@ void main() {
padding: padding,
minimumSize: minimumSize,
fixedSize: fixedSize,
maximumSize: maximumSize,
side: side,
shape: shape,
mouseCursor: mouseCursor,
......@@ -131,6 +136,7 @@ void main() {
padding: padding,
minimumSize: minimumSize,
fixedSize: fixedSize,
maximumSize: maximumSize,
side: side,
shape: shape,
mouseCursor: mouseCursor,
......
......@@ -1172,6 +1172,77 @@ void main() {
expect(tester.getRect(find.byKey(iconKey)), const Rect.fromLTRB(46.0, 0.0, 96.0, 100.0));
expect(tester.getRect(find.byKey(labelKey)), const Rect.fromLTRB(104.0, 0.0, 154.0, 100.0));
});
testWidgets('ElevatedButton maximumSize', (WidgetTester tester) async {
final Key key0 = UniqueKey();
final Key key1 = UniqueKey();
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ElevatedButton(
key: key0,
style: TextButton.styleFrom(
minimumSize: const Size(24, 36),
maximumSize: const Size.fromWidth(64),
),
onPressed: () { },
child: const Text('A B C D E F G H I J K L M N O P'),
),
ElevatedButton.icon(
key: key1,
style: TextButton.styleFrom(
minimumSize: const Size(24, 36),
maximumSize: const Size.fromWidth(104),
),
onPressed: () {},
icon: Container(color: Colors.red, width: 32, height: 32),
label: const Text('A B C D E F G H I J K L M N O P'),
),
],
),
),
),
),
);
expect(tester.getSize(find.byKey(key0)), const Size(64.0, 224.0));
expect(tester.getSize(find.byKey(key1)), const Size(104.0, 224.0));
});
testWidgets('Fixed size ElevatedButton, same as minimumSize == maximumSize', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ElevatedButton(
style: ElevatedButton.styleFrom(fixedSize: const Size(200, 200)),
onPressed: () { },
child: const Text('200x200'),
),
ElevatedButton(
style: ElevatedButton.styleFrom(
minimumSize: const Size(200, 200),
maximumSize: const Size(200, 200),
),
onPressed: () { },
child: const Text('200,200'),
),
],
),
),
),
);
expect(tester.getSize(find.widgetWithText(ElevatedButton, '200x200')), const Size(200, 200));
expect(tester.getSize(find.widgetWithText(ElevatedButton, '200,200')), const Size(200, 200));
});
}
TextStyle _iconStyle(WidgetTester tester, IconData icon) {
......
......@@ -1348,6 +1348,77 @@ void main() {
expect(tester.getRect(find.byKey(iconKey)), const Rect.fromLTRB(46.0, 0.0, 96.0, 100.0));
expect(tester.getRect(find.byKey(labelKey)), const Rect.fromLTRB(104.0, 0.0, 154.0, 100.0));
});
testWidgets('TextButton maximumSize', (WidgetTester tester) async {
final Key key0 = UniqueKey();
final Key key1 = UniqueKey();
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
OutlinedButton(
key: key0,
style: TextButton.styleFrom(
minimumSize: const Size(24, 36),
maximumSize: const Size.fromWidth(64),
),
onPressed: () { },
child: const Text('A B C D E F G H I J K L M N O P'),
),
OutlinedButton.icon(
key: key1,
style: TextButton.styleFrom(
minimumSize: const Size(24, 36),
maximumSize: const Size.fromWidth(104),
),
onPressed: () {},
icon: Container(color: Colors.red, width: 32, height: 32),
label: const Text('A B C D E F G H I J K L M N O P'),
),
],
),
),
),
),
);
expect(tester.getSize(find.byKey(key0)), const Size(64.0, 224.0));
expect(tester.getSize(find.byKey(key1)), const Size(104.0, 224.0));
});
testWidgets('Fixed size OutlinedButton, same as minimumSize == maximumSize', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
OutlinedButton(
style: OutlinedButton.styleFrom(fixedSize: const Size(200, 200)),
onPressed: () { },
child: const Text('200x200'),
),
OutlinedButton(
style: OutlinedButton.styleFrom(
minimumSize: const Size(200, 200),
maximumSize: const Size(200, 200),
),
onPressed: () { },
child: const Text('200,200'),
),
],
),
),
),
);
expect(tester.getSize(find.widgetWithText(OutlinedButton, '200x200')), const Size(200, 200));
expect(tester.getSize(find.widgetWithText(OutlinedButton, '200,200')), const Size(200, 200));
});
}
PhysicalModelLayer _findPhysicalLayer(Element element) {
......
......@@ -1145,6 +1145,78 @@ void main() {
expect(tester.getRect(find.byKey(iconKey)), const Rect.fromLTRB(46.0, 0.0, 96.0, 100.0));
expect(tester.getRect(find.byKey(labelKey)), const Rect.fromLTRB(104.0, 0.0, 154.0, 100.0));
});
testWidgets('TextButton maximumSize', (WidgetTester tester) async {
final Key key0 = UniqueKey();
final Key key1 = UniqueKey();
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
TextButton(
key: key0,
style: TextButton.styleFrom(
minimumSize: const Size(24, 36),
maximumSize: const Size.fromWidth(64),
),
onPressed: () { },
child: const Text('A B C D E F G H I J K L M N O P'),
),
TextButton.icon(
key: key1,
style: TextButton.styleFrom(
minimumSize: const Size(24, 36),
maximumSize: const Size.fromWidth(104),
),
onPressed: () {},
icon: Container(color: Colors.red, width: 32, height: 32),
label: const Text('A B C D E F G H I J K L M N O P'),
),
],
),
),
),
),
);
expect(tester.getSize(find.byKey(key0)), const Size(64.0, 128.0));
expect(tester.getSize(find.byKey(key1)), const Size(104.0, 128.0));
});
testWidgets('Fixed size TextButton, same as minimumSize == maximumSize', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
TextButton(
style: TextButton.styleFrom(fixedSize: const Size(200, 200)),
onPressed: () { },
child: const Text('200x200'),
),
TextButton(
style: TextButton.styleFrom(
minimumSize: const Size(200, 200),
maximumSize: const Size(200, 200),
),
onPressed: () { },
child: const Text('200,200'),
),
],
),
),
),
);
expect(tester.getSize(find.widgetWithText(TextButton, '200x200')), const Size(200, 200));
expect(tester.getSize(find.widgetWithText(TextButton, '200,200')), const Size(200, 200));
});
}
TextStyle? _iconStyle(WidgetTester tester, IconData icon) {
......
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