Added the ability to constrain the size of input decorators (#80754)
This commit is contained in:
parent
5526dcc24b
commit
07a6b8f071
@ -2363,7 +2363,7 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
|
|||||||
: const EdgeInsets.fromLTRB(12.0, 24.0, 12.0, 16.0));
|
: const EdgeInsets.fromLTRB(12.0, 24.0, 12.0, 16.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
return _Decorator(
|
final _Decorator decorator = _Decorator(
|
||||||
decoration: _Decoration(
|
decoration: _Decoration(
|
||||||
contentPadding: contentPadding,
|
contentPadding: contentPadding,
|
||||||
isCollapsed: decoration!.isCollapsed,
|
isCollapsed: decoration!.isCollapsed,
|
||||||
@ -2393,6 +2393,15 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
|
|||||||
isFocused: isFocused,
|
isFocused: isFocused,
|
||||||
expands: widget.expands,
|
expands: widget.expands,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final BoxConstraints? constraints = decoration!.constraints ?? themeData.inputDecorationTheme.constraints;
|
||||||
|
if (constraints != null) {
|
||||||
|
return ConstrainedBox(
|
||||||
|
constraints: constraints,
|
||||||
|
child: decorator,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return decorator;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2563,6 +2572,7 @@ class InputDecoration {
|
|||||||
this.enabled = true,
|
this.enabled = true,
|
||||||
this.semanticCounterText,
|
this.semanticCounterText,
|
||||||
this.alignLabelWithHint,
|
this.alignLabelWithHint,
|
||||||
|
this.constraints,
|
||||||
}) : assert(enabled != null),
|
}) : assert(enabled != null),
|
||||||
assert(!(prefix != null && prefixText != null), 'Declaring both prefix and prefixText is not supported.'),
|
assert(!(prefix != null && prefixText != null), 'Declaring both prefix and prefixText is not supported.'),
|
||||||
assert(!(suffix != null && suffixText != null), 'Declaring both suffix and suffixText is not supported.');
|
assert(!(suffix != null && suffixText != null), 'Declaring both suffix and suffixText is not supported.');
|
||||||
@ -2625,7 +2635,8 @@ class InputDecoration {
|
|||||||
disabledBorder = null,
|
disabledBorder = null,
|
||||||
enabledBorder = null,
|
enabledBorder = null,
|
||||||
semanticCounterText = null,
|
semanticCounterText = null,
|
||||||
alignLabelWithHint = false;
|
alignLabelWithHint = false,
|
||||||
|
constraints = null;
|
||||||
|
|
||||||
/// An icon to show before the input field and outside of the decoration's
|
/// An icon to show before the input field and outside of the decoration's
|
||||||
/// container.
|
/// container.
|
||||||
@ -3320,6 +3331,20 @@ class InputDecoration {
|
|||||||
/// Defaults to false.
|
/// Defaults to false.
|
||||||
final bool? alignLabelWithHint;
|
final bool? alignLabelWithHint;
|
||||||
|
|
||||||
|
/// Defines minimum and maximum sizes for the [InputDecorator].
|
||||||
|
///
|
||||||
|
/// Typically the decorator will fill the horizontal space it is given. For
|
||||||
|
/// larger screens, it may be useful to have the maximum width clamped to
|
||||||
|
/// a given value so it doesn't fill the whole screen. This property
|
||||||
|
/// allows you to control how big the decorator will be in its available
|
||||||
|
/// space.
|
||||||
|
///
|
||||||
|
/// If null, then the ambient [ThemeData.inputDecorationTheme]'s
|
||||||
|
/// [InputDecorationTheme.constraints] will be used. If that
|
||||||
|
/// is null then the decorator will fill the available width with
|
||||||
|
/// a default height based on text size.
|
||||||
|
final BoxConstraints? constraints;
|
||||||
|
|
||||||
/// Creates a copy of this input decoration with the given fields replaced
|
/// Creates a copy of this input decoration with the given fields replaced
|
||||||
/// by the new values.
|
/// by the new values.
|
||||||
InputDecoration copyWith({
|
InputDecoration copyWith({
|
||||||
@ -3367,6 +3392,7 @@ class InputDecoration {
|
|||||||
bool? enabled,
|
bool? enabled,
|
||||||
String? semanticCounterText,
|
String? semanticCounterText,
|
||||||
bool? alignLabelWithHint,
|
bool? alignLabelWithHint,
|
||||||
|
BoxConstraints? constraints,
|
||||||
}) {
|
}) {
|
||||||
return InputDecoration(
|
return InputDecoration(
|
||||||
icon: icon ?? this.icon,
|
icon: icon ?? this.icon,
|
||||||
@ -3413,6 +3439,7 @@ class InputDecoration {
|
|||||||
enabled: enabled ?? this.enabled,
|
enabled: enabled ?? this.enabled,
|
||||||
semanticCounterText: semanticCounterText ?? this.semanticCounterText,
|
semanticCounterText: semanticCounterText ?? this.semanticCounterText,
|
||||||
alignLabelWithHint: alignLabelWithHint ?? this.alignLabelWithHint,
|
alignLabelWithHint: alignLabelWithHint ?? this.alignLabelWithHint,
|
||||||
|
constraints: constraints ?? this.constraints,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3448,6 +3475,7 @@ class InputDecoration {
|
|||||||
enabledBorder: enabledBorder ?? theme.enabledBorder,
|
enabledBorder: enabledBorder ?? theme.enabledBorder,
|
||||||
border: border ?? theme.border,
|
border: border ?? theme.border,
|
||||||
alignLabelWithHint: alignLabelWithHint ?? theme.alignLabelWithHint,
|
alignLabelWithHint: alignLabelWithHint ?? theme.alignLabelWithHint,
|
||||||
|
constraints: constraints ?? theme.constraints,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3501,7 +3529,8 @@ class InputDecoration {
|
|||||||
&& other.border == border
|
&& other.border == border
|
||||||
&& other.enabled == enabled
|
&& other.enabled == enabled
|
||||||
&& other.semanticCounterText == semanticCounterText
|
&& other.semanticCounterText == semanticCounterText
|
||||||
&& other.alignLabelWithHint == alignLabelWithHint;
|
&& other.alignLabelWithHint == alignLabelWithHint
|
||||||
|
&& other.constraints == constraints;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -3553,6 +3582,7 @@ class InputDecoration {
|
|||||||
enabled,
|
enabled,
|
||||||
semanticCounterText,
|
semanticCounterText,
|
||||||
alignLabelWithHint,
|
alignLabelWithHint,
|
||||||
|
constraints,
|
||||||
];
|
];
|
||||||
return hashList(values);
|
return hashList(values);
|
||||||
}
|
}
|
||||||
@ -3600,6 +3630,7 @@ class InputDecoration {
|
|||||||
if (!enabled) 'enabled: false',
|
if (!enabled) 'enabled: false',
|
||||||
if (semanticCounterText != null) 'semanticCounterText: $semanticCounterText',
|
if (semanticCounterText != null) 'semanticCounterText: $semanticCounterText',
|
||||||
if (alignLabelWithHint != null) 'alignLabelWithHint: $alignLabelWithHint',
|
if (alignLabelWithHint != null) 'alignLabelWithHint: $alignLabelWithHint',
|
||||||
|
if (constraints != null) 'constraints: $constraints',
|
||||||
];
|
];
|
||||||
return 'InputDecoration(${description.join(', ')})';
|
return 'InputDecoration(${description.join(', ')})';
|
||||||
}
|
}
|
||||||
@ -3651,6 +3682,7 @@ class InputDecorationTheme with Diagnosticable {
|
|||||||
this.enabledBorder,
|
this.enabledBorder,
|
||||||
this.border,
|
this.border,
|
||||||
this.alignLabelWithHint = false,
|
this.alignLabelWithHint = false,
|
||||||
|
this.constraints,
|
||||||
}) : assert(isDense != null),
|
}) : assert(isDense != null),
|
||||||
assert(isCollapsed != null),
|
assert(isCollapsed != null),
|
||||||
assert(filled != null),
|
assert(filled != null),
|
||||||
@ -3972,6 +4004,23 @@ class InputDecorationTheme with Diagnosticable {
|
|||||||
/// behavior of aligning the label with the center of the [TextField].
|
/// behavior of aligning the label with the center of the [TextField].
|
||||||
final bool alignLabelWithHint;
|
final bool alignLabelWithHint;
|
||||||
|
|
||||||
|
/// Defines minimum and maximum sizes for the [InputDecorator].
|
||||||
|
///
|
||||||
|
/// Typically the decorator will fill the horizontal space it is given. For
|
||||||
|
/// larger screens, it may be useful to have the maximum width clamped to
|
||||||
|
/// a given value so it doesn't fill the whole screen. This property
|
||||||
|
/// allows you to control how big the decorator will be in its available
|
||||||
|
/// space.
|
||||||
|
///
|
||||||
|
/// If null, then the decorator will fill the available width with
|
||||||
|
/// a default height based on text size.
|
||||||
|
///
|
||||||
|
/// See also:
|
||||||
|
///
|
||||||
|
/// * [InputDecoration.constraints], which can override this setting for a
|
||||||
|
/// given decorator.
|
||||||
|
final BoxConstraints? constraints;
|
||||||
|
|
||||||
/// Creates a copy of this object but with the given fields replaced with the
|
/// Creates a copy of this object but with the given fields replaced with the
|
||||||
/// new values.
|
/// new values.
|
||||||
InputDecorationTheme copyWith({
|
InputDecorationTheme copyWith({
|
||||||
@ -4004,6 +4053,7 @@ class InputDecorationTheme with Diagnosticable {
|
|||||||
InputBorder? enabledBorder,
|
InputBorder? enabledBorder,
|
||||||
InputBorder? border,
|
InputBorder? border,
|
||||||
bool? alignLabelWithHint,
|
bool? alignLabelWithHint,
|
||||||
|
BoxConstraints? constraints,
|
||||||
}) {
|
}) {
|
||||||
return InputDecorationTheme(
|
return InputDecorationTheme(
|
||||||
labelStyle: labelStyle ?? this.labelStyle,
|
labelStyle: labelStyle ?? this.labelStyle,
|
||||||
@ -4031,6 +4081,7 @@ class InputDecorationTheme with Diagnosticable {
|
|||||||
enabledBorder: enabledBorder ?? this.enabledBorder,
|
enabledBorder: enabledBorder ?? this.enabledBorder,
|
||||||
border: border ?? this.border,
|
border: border ?? this.border,
|
||||||
alignLabelWithHint: alignLabelWithHint ?? this.alignLabelWithHint,
|
alignLabelWithHint: alignLabelWithHint ?? this.alignLabelWithHint,
|
||||||
|
constraints: constraints ?? this.constraints,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4062,6 +4113,7 @@ class InputDecorationTheme with Diagnosticable {
|
|||||||
enabledBorder,
|
enabledBorder,
|
||||||
border,
|
border,
|
||||||
alignLabelWithHint,
|
alignLabelWithHint,
|
||||||
|
constraints,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4096,6 +4148,7 @@ class InputDecorationTheme with Diagnosticable {
|
|||||||
&& other.enabledBorder == enabledBorder
|
&& other.enabledBorder == enabledBorder
|
||||||
&& other.border == border
|
&& other.border == border
|
||||||
&& other.alignLabelWithHint == alignLabelWithHint
|
&& other.alignLabelWithHint == alignLabelWithHint
|
||||||
|
&& other.constraints == constraints
|
||||||
&& other.disabledBorder == disabledBorder;
|
&& other.disabledBorder == disabledBorder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4128,5 +4181,6 @@ class InputDecorationTheme with Diagnosticable {
|
|||||||
properties.add(DiagnosticsProperty<InputBorder>('enabledBorder', enabledBorder, defaultValue: defaultTheme.enabledBorder));
|
properties.add(DiagnosticsProperty<InputBorder>('enabledBorder', enabledBorder, defaultValue: defaultTheme.enabledBorder));
|
||||||
properties.add(DiagnosticsProperty<InputBorder>('border', border, defaultValue: defaultTheme.border));
|
properties.add(DiagnosticsProperty<InputBorder>('border', border, defaultValue: defaultTheme.border));
|
||||||
properties.add(DiagnosticsProperty<bool>('alignLabelWithHint', alignLabelWithHint, defaultValue: defaultTheme.alignLabelWithHint));
|
properties.add(DiagnosticsProperty<bool>('alignLabelWithHint', alignLabelWithHint, defaultValue: defaultTheme.alignLabelWithHint));
|
||||||
|
properties.add(DiagnosticsProperty<BoxConstraints>('constraints', constraints, defaultValue: defaultTheme.constraints));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1728,6 +1728,49 @@ void main() {
|
|||||||
expect(tester.getTopLeft(find.byKey(prefixKey)).dy, 0.0);
|
expect(tester.getTopLeft(find.byKey(prefixKey)).dy, 0.0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
group('constraints', () {
|
||||||
|
testWidgets('No InputDecorator constraints', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(buildInputDecorator());
|
||||||
|
|
||||||
|
// Should fill the screen width and be default height
|
||||||
|
expect(tester.getSize(find.byType(InputDecorator)), const Size(800, 48));
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('InputDecoratorThemeData constraints', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
buildInputDecorator(
|
||||||
|
theme: ThemeData(
|
||||||
|
inputDecorationTheme: const InputDecorationTheme(
|
||||||
|
constraints: BoxConstraints(maxWidth: 300, maxHeight: 40),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Theme settings should make it 300x40 pixels
|
||||||
|
expect(tester.getSize(find.byType(InputDecorator)), const Size(300, 40));
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('InputDecorator constraints', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
buildInputDecorator(
|
||||||
|
theme: ThemeData(
|
||||||
|
inputDecorationTheme: const InputDecorationTheme(
|
||||||
|
constraints: BoxConstraints(maxWidth: 300, maxHeight: 40),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
constraints: BoxConstraints(maxWidth: 200, maxHeight: 32),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// InputDecoration.constraints should override the theme. It should be
|
||||||
|
// only 200x32 pixels
|
||||||
|
expect(tester.getSize(find.byType(InputDecorator)), const Size(200, 32));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
group('textAlignVertical position', () {
|
group('textAlignVertical position', () {
|
||||||
group('simple case', () {
|
group('simple case', () {
|
||||||
testWidgets('align top (default)', (WidgetTester tester) async {
|
testWidgets('align top (default)', (WidgetTester tester) async {
|
||||||
@ -3139,6 +3182,7 @@ void main() {
|
|||||||
focusColor: Colors.blue,
|
focusColor: Colors.blue,
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
alignLabelWithHint: true,
|
alignLabelWithHint: true,
|
||||||
|
constraints: BoxConstraints(minWidth: 10, maxWidth: 20, minHeight: 30, maxHeight: 40),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -3155,6 +3199,7 @@ void main() {
|
|||||||
expect(decoration.fillColor, Colors.red);
|
expect(decoration.fillColor, Colors.red);
|
||||||
expect(decoration.border, InputBorder.none);
|
expect(decoration.border, InputBorder.none);
|
||||||
expect(decoration.alignLabelWithHint, true);
|
expect(decoration.alignLabelWithHint, true);
|
||||||
|
expect(decoration.constraints, const BoxConstraints(minWidth: 10, maxWidth: 20, minHeight: 30, maxHeight: 40));
|
||||||
|
|
||||||
// InputDecoration (baseDecoration) defines InputDecoration properties
|
// InputDecoration (baseDecoration) defines InputDecoration properties
|
||||||
decoration = const InputDecoration(
|
decoration = const InputDecoration(
|
||||||
@ -3171,6 +3216,7 @@ void main() {
|
|||||||
fillColor: Colors.blue,
|
fillColor: Colors.blue,
|
||||||
border: OutlineInputBorder(),
|
border: OutlineInputBorder(),
|
||||||
alignLabelWithHint: false,
|
alignLabelWithHint: false,
|
||||||
|
constraints: BoxConstraints(minWidth: 10, maxWidth: 20, minHeight: 30, maxHeight: 40),
|
||||||
).applyDefaults(
|
).applyDefaults(
|
||||||
const InputDecorationTheme(
|
const InputDecorationTheme(
|
||||||
labelStyle: themeStyle,
|
labelStyle: themeStyle,
|
||||||
@ -3189,6 +3235,7 @@ void main() {
|
|||||||
focusColor: Colors.blue,
|
focusColor: Colors.blue,
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
alignLabelWithHint: true,
|
alignLabelWithHint: true,
|
||||||
|
constraints: BoxConstraints(minWidth: 40, maxWidth: 30, minHeight: 20, maxHeight: 10),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -3207,6 +3254,7 @@ void main() {
|
|||||||
expect(decoration.fillColor, Colors.blue);
|
expect(decoration.fillColor, Colors.blue);
|
||||||
expect(decoration.border, const OutlineInputBorder());
|
expect(decoration.border, const OutlineInputBorder());
|
||||||
expect(decoration.alignLabelWithHint, false);
|
expect(decoration.alignLabelWithHint, false);
|
||||||
|
expect(decoration.constraints, const BoxConstraints(minWidth: 10, maxWidth: 20, minHeight: 30, maxHeight: 40));
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('InputDecorator OutlineInputBorder fillColor is clipped by border', (WidgetTester tester) async {
|
testWidgets('InputDecorator OutlineInputBorder fillColor is clipped by border', (WidgetTester tester) async {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user