Unverified Commit 89ff794a authored by Shi-Hao Hong's avatar Shi-Hao Hong Committed by GitHub

InputDecorator prefixIconConstraints and suffixIconConstraints (#50058)

parent 8aa67610
......@@ -1923,7 +1923,7 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
InputDecoration _effectiveDecoration;
InputDecoration get decoration {
_effectiveDecoration ??= widget.decoration.applyDefaults(
Theme.of(context).inputDecorationTheme
Theme.of(context).inputDecorationTheme,
);
return _effectiveDecoration;
}
......@@ -2200,7 +2200,7 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
widthFactor: 1.0,
heightFactor: 1.0,
child: ConstrainedBox(
constraints: const BoxConstraints(
constraints: decoration.prefixIconConstraints ?? const BoxConstraints(
minWidth: kMinInteractiveDimension,
minHeight: kMinInteractiveDimension,
),
......@@ -2219,7 +2219,7 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
widthFactor: 1.0,
heightFactor: 1.0,
child: ConstrainedBox(
constraints: const BoxConstraints(
constraints: decoration.suffixIconConstraints ?? const BoxConstraints(
minWidth: kMinInteractiveDimension,
minHeight: kMinInteractiveDimension,
),
......@@ -2463,6 +2463,7 @@ class InputDecoration {
this.isDense,
this.contentPadding,
this.prefixIcon,
this.prefixIconConstraints,
this.prefix,
this.prefixText,
this.prefixStyle,
......@@ -2470,6 +2471,7 @@ class InputDecoration {
this.suffix,
this.suffixText,
this.suffixStyle,
this.suffixIconConstraints,
this.counter,
this.counterText,
this.counterStyle,
......@@ -2533,10 +2535,12 @@ class InputDecoration {
prefix = null,
prefixText = null,
prefixStyle = null,
prefixIconConstraints = null,
suffix = null,
suffixIcon = null,
suffixText = null,
suffixStyle = null,
suffixIconConstraints = null,
counter = null,
counterText = null,
counterStyle = null,
......@@ -2754,6 +2758,58 @@ class InputDecoration {
/// * [suffixIcon], which is the same but on the trailing edge.
final Widget prefixIcon;
/// The constraints for the prefix icon.
///
/// This can be used to modify the [BoxConstraints] surrounding [prefixIcon].
///
/// This property is particularly useful for getting the decoration's height
/// less than 48px. This can be achieved by setting [isDense] to true and
/// setting the constraints' minimum height and width to a value lower than
/// 48px.
///
/// {@tool dartpad --template=stateless_widget_scaffold}
/// This example shows the differences between two `TextField` widgets when
/// [prefixIconConstraints] is set to the default value and when one is not.
///
/// Note that [isDense] must be set to true to be able to
/// set the constraints smaller than 48px.
///
/// If null, [BoxConstraints] with a minimum width and height of 48px is
/// used.
///
/// ```dart
/// Widget build(BuildContext context) {
/// return Padding(
/// padding: const EdgeInsets.symmetric(horizontal: 8.0),
/// child: Column(
/// mainAxisAlignment: MainAxisAlignment.center,
/// children: <Widget>[
/// TextField(
/// decoration: InputDecoration(
/// hintText: 'Normal Icon Constraints',
/// prefixIcon: Icon(Icons.search),
/// ),
/// ),
/// SizedBox(height: 10),
/// TextField(
/// decoration: InputDecoration(
/// isDense: true,
/// hintText:'Smaller Icon Constraints',
/// prefixIcon: Icon(Icons.search),
/// prefixIconConstraints: BoxConstraints(
/// minHeight: 32,
/// minWidth: 32,
/// ),
/// ),
/// ),
/// ],
/// ),
/// );
/// }
/// ```
/// {@end-tool}
final BoxConstraints prefixIconConstraints;
/// Optional widget to place on the line before the input.
///
/// This can be used, for example, to add some padding to text that would
......@@ -2867,6 +2923,61 @@ class InputDecoration {
/// * [prefixStyle], the equivalent but on the leading edge.
final TextStyle suffixStyle;
/// The constraints for the suffix icon.
///
/// This can be used to modify the [BoxConstraints] surrounding [suffixIcon].
///
/// This property is particularly useful for getting the decoration's height
/// less than 48px. This can be achieved by setting [isDense] to true and
/// setting the constraints' minimum height and width to a value lower than
/// 48px.
///
/// If null, a [BoxConstraints] with a minimum width and height of 48px is
/// used.
///
/// {@tool dartpad --template=stateless_widget_scaffold}
/// This example shows the differences between two `TextField` widgets when
/// [suffixIconConstraints] is set to the default value and when one is not.
///
/// Note that [isDense] must be set to true to be able to
/// set the constraints smaller than 48px.
///
/// If null, [BoxConstraints] with a minimum width and height of 48px is
/// used.
///
/// ```dart
/// Widget build(BuildContext context) {
/// return Padding(
/// padding: const EdgeInsets.symmetric(horizontal: 8.0),
/// child: Column(
/// mainAxisAlignment: MainAxisAlignment.center,
/// children: <Widget>[
/// TextField(
/// decoration: InputDecoration(
/// hintText: 'Normal Icon Constraints',
/// suffixIcon: Icon(Icons.search),
/// ),
/// ),
/// SizedBox(height: 10),
/// TextField(
/// decoration: InputDecoration(
/// isDense: true,
/// hintText:'Smaller Icon Constraints',
/// suffixIcon: Icon(Icons.search),
/// suffixIconConstraints: BoxConstraints(
/// minHeight: 32,
/// minWidth: 32,
/// ),
/// ),
/// ),
/// ],
/// ),
/// );
/// }
/// ```
/// {@end-tool}
final BoxConstraints suffixIconConstraints;
/// Optional text to place below the line as a character count.
///
/// Rendered using [counterStyle]. Uses [helperStyle] if [counterStyle] is
......@@ -3151,11 +3262,13 @@ class InputDecoration {
Widget prefixIcon,
Widget prefix,
String prefixText,
BoxConstraints prefixIconConstraints,
TextStyle prefixStyle,
Widget suffixIcon,
Widget suffix,
String suffixText,
TextStyle suffixStyle,
BoxConstraints suffixIconConstraints,
Widget counter,
String counterText,
TextStyle counterStyle,
......@@ -3195,10 +3308,12 @@ class InputDecoration {
prefix: prefix ?? this.prefix,
prefixText: prefixText ?? this.prefixText,
prefixStyle: prefixStyle ?? this.prefixStyle,
prefixIconConstraints: prefixIconConstraints ?? this.prefixIconConstraints,
suffixIcon: suffixIcon ?? this.suffixIcon,
suffix: suffix ?? this.suffix,
suffixText: suffixText ?? this.suffixText,
suffixStyle: suffixStyle ?? this.suffixStyle,
suffixIconConstraints: suffixIconConstraints ?? this.suffixIconConstraints,
counter: counter ?? this.counter,
counterText: counterText ?? this.counterText,
counterStyle: counterStyle ?? this.counterStyle,
......@@ -3282,10 +3397,12 @@ class InputDecoration {
&& other.prefix == prefix
&& other.prefixText == prefixText
&& other.prefixStyle == prefixStyle
&& other.prefixIconConstraints == prefixIconConstraints
&& other.suffixIcon == suffixIcon
&& other.suffix == suffix
&& other.suffixText == suffixText
&& other.suffixStyle == suffixStyle
&& other.suffixIconConstraints == suffixIconConstraints
&& other.counter == counter
&& other.counterText == counterText
&& other.counterStyle == counterStyle
......@@ -3334,10 +3451,12 @@ class InputDecoration {
prefix,
prefixText,
prefixStyle,
prefixIconConstraints,
suffixIcon,
suffix,
suffixText,
suffixStyle,
suffixIconConstraints,
counter,
counterText,
counterStyle,
......@@ -3376,10 +3495,12 @@ class InputDecoration {
if (prefix != null) 'prefix: $prefix',
if (prefixText != null) 'prefixText: $prefixText',
if (prefixStyle != null) 'prefixStyle: $prefixStyle',
if (prefixIconConstraints != null) 'prefixIconConstraints: $prefixIconConstraints',
if (suffixIcon != null) 'suffixIcon: $suffixIcon',
if (suffix != null) 'suffix: $suffix',
if (suffixText != null) 'suffixText: $suffixText',
if (suffixStyle != null) 'suffixStyle: $suffixStyle',
if (suffixIconConstraints != null) 'suffixIconConstraints: $suffixIconConstraints',
if (counter != null) 'counter: $counter',
if (counterText != null) 'counterText: $counterText',
if (counterStyle != null) 'counterStyle: $counterStyle',
......
......@@ -1433,6 +1433,43 @@ void main() {
expect(tester.getTopRight(find.text('text')).dx, lessThanOrEqualTo(tester.getTopLeft(find.byIcon(Icons.satellite)).dx));
});
testWidgets('InputDecorator prefixIconConstraints/suffixIconConstraints', (WidgetTester tester) async {
await tester.pumpWidget(
buildInputDecorator(
// isEmpty: false (default)
// isFocused: false (default)
decoration: const InputDecoration(
prefixIcon: Icon(Icons.pages),
prefixIconConstraints: BoxConstraints(
minWidth: 32,
minHeight: 32,
),
suffixIcon: Icon(Icons.satellite),
suffixIconConstraints: BoxConstraints(
minWidth: 25,
minHeight: 25,
),
isDense: true, // has to be true to go below 48px height
),
),
);
// Overall height for this InputDecorator is 32px because the prefix icon
// is now a custom value
expect(tester.getSize(find.byType(InputDecorator)), const Size(800.0, 32.0));
expect(tester.getSize(find.text('text')).height, 16.0);
expect(tester.getSize(find.byIcon(Icons.pages)).height, 32.0);
expect(tester.getSize(find.byIcon(Icons.satellite)).height, 25.0);
// (InputDecorator height - Text widget height) / 2
expect(tester.getTopLeft(find.text('text')).dy, (32.0 - 16.0) / 2);
// prefixIcon should take up the entire height of InputDecorator
expect(tester.getTopLeft(find.byIcon(Icons.pages)).dy, 0.0);
// (InputDecorator height - suffixIcon height) / 2
expect(tester.getTopLeft(find.byIcon(Icons.satellite)).dy, (32.0 - 25.0) / 2);
expect(tester.getTopRight(find.byIcon(Icons.satellite)).dx, 800.0);
});
testWidgets('prefix/suffix icons are centered when smaller than 48 by 48', (WidgetTester tester) async {
const Key prefixKey = Key('prefix');
await tester.pumpWidget(
......
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