Extend InputDecoration borders for disabled/error/focused states (#19694)

Added five InputBorder properties to InputDecoration etc so that apps can control the appearance of an InputDecorator's border:  errorBorder, focusedBorder, focusedErrorBorder, disabledBorder, enabledBorder.
This commit is contained in:
Hans Muller 2018-07-24 08:57:27 -07:00 committed by GitHub
parent 56800d8fa1
commit 0863367c6e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 506 additions and 51 deletions

View file

@ -1591,21 +1591,26 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
return themeData.textTheme.caption.copyWith(color: color).merge(decoration.errorStyle);
}
double get _borderWeight {
if (decoration.isCollapsed || decoration.border == InputBorder.none || !decoration.enabled)
return 0.0;
return isFocused ? 2.0 : 1.0;
}
Color _getBorderColor(ThemeData themeData) {
if (!decoration.enabled) {
if (decoration.filled == true && !decoration.border.isOutline)
return Colors.transparent;
return themeData.disabledColor;
InputBorder _getDefaultBorder(ThemeData themeData) {
Color borderColor;
if (decoration.enabled) {
borderColor = decoration.errorText == null
? _getActiveColor(themeData)
: themeData.errorColor;
} else {
borderColor = (decoration.filled == true && decoration.border?.isOutline != true)
? Colors.transparent
: themeData.disabledColor;
}
return decoration.errorText == null
? _getActiveColor(themeData)
: themeData.errorColor;
double borderWeight;
if (decoration.isCollapsed || decoration?.border == InputBorder.none || !decoration.enabled)
borderWeight = 0.0;
else
borderWeight = isFocused ? 2.0 : 1.0;
final InputBorder border = decoration.border ?? const UnderlineInputBorder();
return border.copyWith(borderSide: new BorderSide(color: borderColor, width: borderWeight));
}
@override
@ -1627,23 +1632,22 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
),
);
final InputBorder border = decoration.border.copyWith(
borderSide: new BorderSide(
color: _getBorderColor(themeData),
width: _borderWeight,
),
);
final bool isError = decoration.errorText != null;
InputBorder border;
if (!decoration.enabled)
border = isError ? decoration.errorBorder : decoration.disabledBorder;
else if (isFocused)
border = isError ? decoration.focusedErrorBorder : decoration.focusedBorder;
else
border = isError ? decoration.errorBorder : decoration.enabledBorder;
border ??= _getDefaultBorder(themeData);
final Widget container = border == null
? new DecoratedBox(
decoration: new BoxDecoration(color: _getFillColor(themeData))
)
: new _BorderContainer(
border: border,
gap: _borderGap,
gapAnimation: _floatingLabelController.view,
fillColor: _getFillColor(themeData),
);
final Widget container = new _BorderContainer(
border: border,
gap: _borderGap,
gapAnimation: _floatingLabelController.view,
fillColor: _getFillColor(themeData),
);
final TextStyle inlineLabelStyle = inlineStyle.merge(decoration.labelStyle);
final Widget label = decoration.labelText == null ? null : new _Shaker(
@ -1759,7 +1763,7 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
if (decoration.isCollapsed) {
floatingLabelHeight = 0.0;
contentPadding = decorationContentPadding ?? EdgeInsets.zero;
} else if (!decoration.border.isOutline) {
} else if (!border.isOutline) {
// 4.0: the vertical gap between the inline elements and the floating label.
floatingLabelHeight = 4.0 + 0.75 * inlineLabelStyle.fontSize;
if (decoration.filled == true) { // filled == null same as filled == false
@ -1786,7 +1790,7 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
isCollapsed: decoration.isCollapsed,
floatingLabelHeight: floatingLabelHeight,
floatingLabelProgress: _floatingLabelController.value,
border: decoration.border,
border: border,
borderGap: _borderGap,
icon: icon,
input: widget.child,
@ -1856,6 +1860,11 @@ class InputDecoration {
this.counterStyle,
this.filled,
this.fillColor,
this.errorBorder,
this.focusedBorder,
this.focusedErrorBorder,
this.disabledBorder,
this.enabledBorder,
this.border,
this.enabled = true,
}) : assert(enabled != null), isCollapsed = false;
@ -1891,7 +1900,12 @@ class InputDecoration {
suffixText = null,
suffixStyle = null,
counterText = null,
counterStyle = null;
counterStyle = null,
errorBorder = null,
focusedBorder = null,
focusedErrorBorder = null,
disabledBorder = null,
enabledBorder = null;
/// An icon to show before the input field and outside of the decoration's
/// container.
@ -2119,16 +2133,147 @@ class InputDecoration {
/// [errorText], and [counterText].
final Color fillColor;
/// The border to draw around the decoration's container.
/// The border to display when the [InputDecorator] does not have the focus and
/// is showing an error.
///
/// See also:
/// * [InputDecorator.isFocused], which is true if the [InputDecorator]'s child
/// has the focus.
/// * [InputDecoration.errorText], the error shown by the [InputDecorator], if non-null.
/// * [border], for a description of where the [InputDecorator] border appears.
/// * [UnderlineInputBorder], an [InputDecorator] border which draws a horizontal
/// line at the bottom of the input decorator's container.
/// * [OutlineInputBorder], an [InputDecorator] border which draws a
/// rounded rectangle around the input decorator's container.
/// * [InputBorder.none], which doesn't draw a border.
/// * [focusedBorder], displayed when [InputDecorator.isFocused] is true
/// and [InputDecoration.errorText] is null.
/// * [focusedErrorBorder], displayed when [InputDecorator.isFocused] is true
/// and [InputDecoration.errorText] is non-null.
/// * [disabledBorder], displayed when [InputDecoration.enabled] is false
/// and [InputDecoration.errorText] is null.
/// * [enabledBorder], displayed when [InputDecoration.enabled] is true
/// and [InputDecoration.errorText] is null.
final InputBorder errorBorder;
/// The border to display when the [InputDecorator] has the focus and is not
/// showing an error.
///
/// See also:
///
/// * [InputDecorator.isFocused], which is true if the [InputDecorator]'s child
/// has the focus.
/// * [InputDecoration.errorText], the error shown by the [InputDecorator], if non-null.
/// * [border], for a description of where the [InputDecorator] border appears.
/// * [UnderlineInputBorder], an [InputDecorator] border which draws a horizontal
/// line at the bottom of the input decorator's container.
/// * [OutlineInputBorder], an [InputDecorator] border which draws a
/// rounded rectangle around the input decorator's container.
/// * [InputBorder.none], which doesn't draw a border.
/// * [errorBorder], displayed when [InputDecorator.isFocused] is false
/// and [InputDecoration.errorText] is non-null.
/// * [focusedErrorBorder], displayed when [InputDecorator.isFocused] is true
/// and [InputDecoration.errorText] is non-null.
/// * [disabledBorder], displayed when [InputDecoration.enabled] is false
/// and [InputDecoration.errorText] is null.
/// * [enabledBorder], displayed when [InputDecoration.enabled] is true
/// and [InputDecoration.errorText] is null.
final InputBorder focusedBorder;
/// The border to display when the [InputDecorator] has the focus and is
/// showing an error.
///
/// See also:
///
/// * [InputDecorator.isFocused], which is true if the [InputDecorator]'s child
/// has the focus.
/// * [InputDecoration.errorText], the error shown by the [InputDecorator], if non-null.
/// * [border], for a description of where the [InputDecorator] border appears.
/// * [UnderlineInputBorder], an [InputDecorator] border which draws a horizontal
/// line at the bottom of the input decorator's container.
/// * [OutlineInputBorder], an [InputDecorator] border which draws a
/// rounded rectangle around the input decorator's container.
/// * [InputBorder.none], which doesn't draw a border.
/// * [errorBorder], displayed when [InputDecorator.isFocused] is false
/// and [InputDecoration.errorText] is non-null.
/// * [focusedBorder], displayed when [InputDecorator.isFocused] is true
/// and [InputDecoration.errorText] is null.
/// * [disabledBorder], displayed when [InputDecoration.enabled] is false
/// and [InputDecoration.errorText] is null.
/// * [enabledBorder], displayed when [InputDecoration.enabled] is true
/// and [InputDecoration.errorText] is null.
final InputBorder focusedErrorBorder;
/// The border to display when the [InputDecorator] is disabled and is not
/// showing an error.
///
/// See also:
///
/// * [InputDecoration.enabled], which is false if the [InputDecorator] is disabled.
/// * [InputDecoration.errorText], the error shown by the [InputDecorator], if non-null.
/// * [border], for a description of where the [InputDecorator] border appears.
/// * [UnderlineInputBorder], an [InputDecorator] border which draws a horizontal
/// line at the bottom of the input decorator's container.
/// * [OutlineInputBorder], an [InputDecorator] border which draws a
/// rounded rectangle around the input decorator's container.
/// * [InputBorder.none], which doesn't draw a border.
/// * [errorBorder], displayed when [InputDecorator.isFocused] is false
/// and [InputDecoration.errorText] is non-null.
/// * [focusedBorder], displayed when [InputDecorator.isFocused] is true
/// and [InputDecoration.errorText] is null.
/// * [focusedErrorBorder], displayed when [InputDecorator.isFocused] is true
/// and [InputDecoration.errorText] is non-null.
/// * [enabledBorder], displayed when [InputDecoration.enabled] is true
/// and [InputDecoration.errorText] is null.
final InputBorder disabledBorder;
/// The border to display when the [InputDecorator] is enabled and is not
/// showing an error.
///
/// See also:
///
/// * [InputDecoration.enabled], which is false if the [InputDecorator] is disabled.
/// * [InputDecoration.errorText], the error shown by the [InputDecorator], if non-null.
/// * [border], for a description of where the [InputDecorator] border appears.
/// * [UnderlineInputBorder], an [InputDecorator] border which draws a horizontal
/// line at the bottom of the input decorator's container.
/// * [OutlineInputBorder], an [InputDecorator] border which draws a
/// rounded rectangle around the input decorator's container.
/// * [InputBorder.none], which doesn't draw a border.
/// * [errorBorder], displayed when [InputDecorator.isFocused] is false
/// and [InputDecoration.errorText] is non-null.
/// * [focusedBorder], displayed when [InputDecorator.isFocused] is true
/// and [InputDecoration.errorText] is null.
/// * [focusedErrorBorder], displayed when [InputDecorator.isFocused] is true
/// and [InputDecoration.errorText] is non-null.
/// * [disabledBorder], displayed when [InputDecoration.enabled] is false
/// and [InputDecoration.errorText] is null.
final InputBorder enabledBorder;
/// The shape of the border to draw around the decoration's container.
///
/// The decoration's container is the area which is filled if [isFilled] is
/// true and bordered per the [border]. It's the area adjacent to
/// [decoration.icon] and above the widgets that contain [helperText],
/// [errorText], and [counterText].
/// [InputDecoration.icon] and above the widgets that contain
/// [InputDecoration.helperText], [InputDecoration.errorText], and
/// [InputDecoration.counterText].
///
/// The default value of this property is `const UnderlineInputBorder()`.
/// The border's bounds, i.e. the value of `border.getOuterPath()`, define
/// the area to be filled.
///
/// This property is only used when the appropriate one of [errorBorder],
/// [focusedBorder], [focusedErrorBorder], [disabledBorder], or [enabledBorder]
/// is not specified. This border's [InputBorder.borderSide] property is
/// configured by the InputDecorator, depending on the values of
/// [InputDecoration.errorText], [InputDecoration.enabled],
/// [InputDecorator.isFocused and the current [Theme].
///
/// Typically one of [UnderlineInputBorder] or [OutlineInputBorder].
/// If null, InputDecorator's default is `const UnderlineInputBorder()`.
///
/// See also:
///
/// * [InputBorder.none], which doesn't draw a border.
/// * [UnderlineInputBorder], which draws a horizontal line at the
/// bottom of the input decorator's container.
/// * [OutlineInputBorder], an [InputDecorator] border which draws a
@ -2168,6 +2313,11 @@ class InputDecoration {
TextStyle counterStyle,
bool filled,
Color fillColor,
InputBorder errorBorder,
InputBorder focusedBorder,
InputBorder focusedErrorBorder,
InputBorder disabledBorder,
InputBorder enabledBorder,
InputBorder border,
bool enabled,
}) {
@ -2194,6 +2344,11 @@ class InputDecoration {
counterStyle: counterStyle ?? this.counterStyle,
filled: filled ?? this.filled,
fillColor: fillColor ?? this.fillColor,
errorBorder: errorBorder ?? this.errorBorder,
focusedBorder: focusedBorder ?? this.focusedBorder,
focusedErrorBorder: focusedErrorBorder ?? this.focusedErrorBorder,
disabledBorder: disabledBorder ?? this.disabledBorder,
enabledBorder: enabledBorder ?? this.enabledBorder,
border: border ?? this.border,
enabled: enabled ?? this.enabled,
);
@ -2218,6 +2373,11 @@ class InputDecoration {
counterStyle: counterStyle ?? theme.counterStyle,
filled: filled ?? theme.filled,
fillColor: fillColor ?? theme.fillColor,
errorBorder: errorBorder ?? theme.errorBorder,
focusedBorder: focusedBorder ?? theme.focusedBorder,
focusedErrorBorder: focusedErrorBorder ?? theme.focusedErrorBorder,
disabledBorder: disabledBorder ?? theme.disabledBorder,
enabledBorder: enabledBorder ?? theme.enabledBorder,
border: border ?? theme.border,
);
}
@ -2252,6 +2412,11 @@ class InputDecoration {
&& typedOther.counterStyle == counterStyle
&& typedOther.filled == filled
&& typedOther.fillColor == fillColor
&& typedOther.errorBorder == errorBorder
&& typedOther.focusedBorder == focusedBorder
&& typedOther.focusedErrorBorder == focusedErrorBorder
&& typedOther.disabledBorder == disabledBorder
&& typedOther.enabledBorder == enabledBorder
&& typedOther.border == border
&& typedOther.enabled == enabled;
}
@ -2265,12 +2430,12 @@ class InputDecoration {
helperText,
helperStyle,
hintText,
hintStyle,
errorText,
errorStyle,
errorMaxLines,
isDense,
hashValues( // Over 20 fields...
hintStyle,
errorText,
errorStyle,
errorMaxLines,
isDense,
contentPadding,
isCollapsed,
prefixIcon,
@ -2283,6 +2448,11 @@ class InputDecoration {
counterStyle,
filled,
fillColor,
errorBorder,
focusedBorder,
focusedErrorBorder,
disabledBorder,
enabledBorder,
border,
enabled,
),
@ -2332,6 +2502,16 @@ class InputDecoration {
description.add('filled: true');
if (fillColor != null)
description.add('fillColor: $fillColor');
if (errorBorder != null)
description.add('errorBorder: $errorBorder');
if (focusedBorder != null)
description.add('focusedBorder: $focusedBorder');
if (focusedErrorBorder != null)
description.add('focusedErrorBorder: $focusedErrorBorder');
if (disabledBorder != null)
description.add('disabledBorder: $disabledBorder');
if (enabledBorder != null)
description.add('enabledBorder: $enabledBorder');
if (border != null)
description.add('border: $border');
if (!enabled)
@ -2370,11 +2550,15 @@ class InputDecorationTheme extends Diagnosticable {
this.counterStyle,
this.filled = false,
this.fillColor,
this.border = const UnderlineInputBorder(),
this.errorBorder,
this.focusedBorder,
this.focusedErrorBorder,
this.disabledBorder,
this.enabledBorder,
this.border,
}) : assert(isDense != null),
assert(isCollapsed != null),
assert(filled != null),
assert(border != null);
assert(filled != null);
/// The style to use for [InputDecoration.labelText] when the label is
/// above (i.e., vertically adjacent to) the input field.
@ -2476,7 +2660,124 @@ class InputDecorationTheme extends Diagnosticable {
/// true and bordered per the [border].
final Color fillColor;
/// The border to draw around the decoration's container.
/// The border to display when the [InputDecorator] does not have the focus and
/// is showing an error.
///
/// See also:
/// * [InputDecorator.isFocused], which is true if the [InputDecorator]'s child
/// has the focus.
/// * [InputDecoration.errorText], the error shown by the [InputDecorator], if non-null.
/// * [border], for a description of where the [InputDecorator] border appears.
/// * [UnderlineInputBorder], an [InputDecorator] border which draws a horizontal
/// line at the bottom of the input decorator's container.
/// * [OutlineInputBorder], an [InputDecorator] border which draws a
/// rounded rectangle around the input decorator's container.
/// * [InputBorder.none], which doesn't draw a border.
/// * [focusedBorder], displayed when [InputDecorator.isFocused] is true
/// and [InputDecoration.errorText] is null.
/// * [focusedErrorBorder], displayed when [InputDecorator.isFocused] is true
/// and [InputDecoration.errorText] is non-null.
/// * [disabledBorder], displayed when [InputDecoration.enabled] is false
/// and [InputDecoration.errorText] is null.
/// * [enabledBorder], displayed when [InputDecoration.enabled] is true
/// and [InputDecoration.errorText] is null.
final InputBorder errorBorder;
/// The border to display when the [InputDecorator] has the focus and is not
/// showing an error.
///
/// See also:
///
/// * [InputDecorator.isFocused], which is true if the [InputDecorator]'s child
/// has the focus.
/// * [InputDecoration.errorText], the error shown by the [InputDecorator], if non-null.
/// * [border], for a description of where the [InputDecorator] border appears.
/// * [UnderlineInputBorder], an [InputDecorator] border which draws a horizontal
/// line at the bottom of the input decorator's container.
/// * [OutlineInputBorder], an [InputDecorator] border which draws a
/// rounded rectangle around the input decorator's container.
/// * [InputBorder.none], which doesn't draw a border.
/// * [errorBorder], displayed when [InputDecorator.isFocused] is false
/// and [InputDecoration.errorText] is non-null.
/// * [focusedErrorBorder], displayed when [InputDecorator.isFocused] is true
/// and [InputDecoration.errorText] is non-null.
/// * [disabledBorder], displayed when [InputDecoration.enabled] is false
/// and [InputDecoration.errorText] is null.
/// * [enabledBorder], displayed when [InputDecoration.enabled] is true
/// and [InputDecoration.errorText] is null.
final InputBorder focusedBorder;
/// The border to display when the [InputDecorator] has the focus and is
/// showing an error.
///
/// See also:
///
/// * [InputDecorator.isFocused], which is true if the [InputDecorator]'s child
/// has the focus.
/// * [InputDecoration.errorText], the error shown by the [InputDecorator], if non-null.
/// * [border], for a description of where the [InputDecorator] border appears.
/// * [UnderlineInputBorder], an [InputDecorator] border which draws a horizontal
/// line at the bottom of the input decorator's container.
/// * [OutlineInputBorder], an [InputDecorator] border which draws a
/// rounded rectangle around the input decorator's container.
/// * [InputBorder.none], which doesn't draw a border.
/// * [errorBorder], displayed when [InputDecorator.isFocused] is false
/// and [InputDecoration.errorText] is non-null.
/// * [focusedBorder], displayed when [InputDecorator.isFocused] is true
/// and [InputDecoration.errorText] is null.
/// * [disabledBorder], displayed when [InputDecoration.enabled] is false
/// and [InputDecoration.errorText] is null.
/// * [enabledBorder], displayed when [InputDecoration.enabled] is true
/// and [InputDecoration.errorText] is null.
final InputBorder focusedErrorBorder;
/// The border to display when the [InputDecorator] is disabled and is not
/// showing an error.
///
/// See also:
///
/// * [InputDecoration.enabled], which is false if the [InputDecorator] is disabled.
/// * [InputDecoration.errorText], the error shown by the [InputDecorator], if non-null.
/// * [border], for a description of where the [InputDecorator] border appears.
/// * [UnderlineInputBorder], an [InputDecorator] border which draws a horizontal
/// line at the bottom of the input decorator's container.
/// * [OutlineInputBorder], an [InputDecorator] border which draws a
/// rounded rectangle around the input decorator's container.
/// * [InputBorder.none], which doesn't draw a border.
/// * [errorBorder], displayed when [InputDecorator.isFocused] is false
/// and [InputDecoration.errorText] is non-null.
/// * [focusedBorder], displayed when [InputDecorator.isFocused] is true
/// and [InputDecoration.errorText] is null.
/// * [focusedErrorBorder], displayed when [InputDecorator.isFocused] is true
/// and [InputDecoration.errorText] is non-null.
/// * [enabledBorder], displayed when [InputDecoration.enabled] is true
/// and [InputDecoration.errorText] is null.
final InputBorder disabledBorder;
/// The border to display when the [InputDecorator] is enabled and is not
/// showing an error.
///
/// See also:
///
/// * [InputDecoration.enabled], which is false if the [InputDecorator] is disabled.
/// * [InputDecoration.errorText], the error shown by the [InputDecorator], if non-null.
/// * [border], for a description of where the [InputDecorator] border appears.
/// * [UnderlineInputBorder], an [InputDecorator] border which draws a horizontal
/// line at the bottom of the input decorator's container.
/// * [OutlineInputBorder], an [InputDecorator] border which draws a
/// rounded rectangle around the input decorator's container.
/// * [InputBorder.none], which doesn't draw a border.
/// * [errorBorder], displayed when [InputDecorator.isFocused] is false
/// and [InputDecoration.errorText] is non-null.
/// * [focusedBorder], displayed when [InputDecorator.isFocused] is true
/// and [InputDecoration.errorText] is null.
/// * [focusedErrorBorder], displayed when [InputDecorator.isFocused] is true
/// and [InputDecoration.errorText] is non-null.
/// * [disabledBorder], displayed when [InputDecoration.enabled] is false
/// and [InputDecoration.errorText] is null.
final InputBorder enabledBorder;
/// The shape of the border to draw around the decoration's container.
///
/// The decoration's container is the area which is filled if [isFilled] is
/// true and bordered per the [border]. It's the area adjacent to
@ -2484,12 +2785,21 @@ class InputDecorationTheme extends Diagnosticable {
/// [InputDecoration.helperText], [InputDecoration.errorText], and
/// [InputDecoration.counterText].
///
/// The default value of this property is `const UnderlineInputBorder()`.
///
/// The border's bounds, i.e. the value of `border.getOuterPath()`, defines
/// The border's bounds, i.e. the value of `border.getOuterPath()`, define
/// the area to be filled.
///
/// This property is only used when the appropriate one of [errorBorder],
/// [focusedBorder], [focusedErrorBorder], [disabledBorder], or [enabledBorder]
/// is not specified. This border's [InputBorder.borderSide] property is
/// configured by the InputDecorator, depending on the values of
/// [InputDecoration.errorText], [InputDecoration.enabled],
/// [InputDecorator.isFocused and the current [Theme].
///
/// Typically one of [UnderlineInputBorder] or [OutlineInputBorder].
/// If null, InputDecorator's default is `const UnderlineInputBorder()`.
///
/// See also:
///
/// * [InputBorder.none], which doesn't draw a border.
/// * [UnderlineInputBorder], which draws a horizontal line at the
/// bottom of the input decorator's container.
@ -2514,6 +2824,11 @@ class InputDecorationTheme extends Diagnosticable {
properties.add(new DiagnosticsProperty<TextStyle>('counterStyle', counterStyle, defaultValue: defaultTheme.counterStyle));
properties.add(new DiagnosticsProperty<bool>('filled', filled, defaultValue: defaultTheme.filled));
properties.add(new DiagnosticsProperty<Color>('fillColor', fillColor, defaultValue: defaultTheme.fillColor));
properties.add(new DiagnosticsProperty<InputBorder>('errorBorder', errorBorder, defaultValue: defaultTheme.errorBorder));
properties.add(new DiagnosticsProperty<InputBorder>('focusedBorder', focusedBorder, defaultValue: defaultTheme.focusedErrorBorder));
properties.add(new DiagnosticsProperty<InputBorder>('focusedErrorborder', focusedErrorBorder, defaultValue: defaultTheme.focusedErrorBorder));
properties.add(new DiagnosticsProperty<InputBorder>('disabledBorder', disabledBorder, defaultValue: defaultTheme.disabledBorder));
properties.add(new DiagnosticsProperty<InputBorder>('enabledBorder', enabledBorder, defaultValue: defaultTheme.enabledBorder));
properties.add(new DiagnosticsProperty<InputBorder>('border', border, defaultValue: defaultTheme.border));
}
}

View file

@ -62,7 +62,7 @@ double getBorderBottom(WidgetTester tester) {
return box.size.height;
}
BorderSide getBorderSide(WidgetTester tester) {
InputBorder getBorder(WidgetTester tester) {
if (!tester.any(findBorderPainter()))
return null;
final CustomPaint customPaint = tester.widget(findBorderPainter());
@ -70,7 +70,11 @@ BorderSide getBorderSide(WidgetTester tester) {
final dynamic/*_InputBorderTween */ inputBorderTween = inputBorderPainter.border;
final Animation<double> animation = inputBorderPainter.borderAnimation;
final dynamic/*_InputBorder */ border = inputBorderTween.evaluate(animation);
return border.borderSide;
return border;
}
BorderSide getBorderSide(WidgetTester tester) {
return getBorder(tester)?.borderSide;
}
double getBorderWeight(WidgetTester tester) => getBorderSide(tester)?.width;
@ -1650,4 +1654,140 @@ void main() {
contains('contentPadding: EdgeInsetsDirectional(5.0, 0.0, 0.0, 0.0)'),
);
});
testWidgets('InputDecoration borders', (WidgetTester tester) async {
const InputBorder errorBorder = OutlineInputBorder(
borderSide: BorderSide(color: Colors.red, width: 1.5),
);
const InputBorder focusedBorder = OutlineInputBorder(
borderSide: BorderSide(color: Colors.green, width: 4.0),
);
const InputBorder focusedErrorBorder = OutlineInputBorder(
borderSide: BorderSide(color: Colors.teal, width: 5.0),
);
const InputBorder disabledBorder = OutlineInputBorder(
borderSide: BorderSide(color: Colors.grey, width: 0.0),
);
const InputBorder enabledBorder = OutlineInputBorder(
borderSide: BorderSide(color: Colors.blue, width: 2.5),
);
await tester.pumpWidget(
buildInputDecorator(
// isFocused: false (default)
decoration: const InputDecoration(
// errorText: null (default)
// enabled: true (default)
errorBorder: errorBorder,
focusedBorder: focusedBorder,
focusedErrorBorder: focusedErrorBorder,
disabledBorder: disabledBorder,
enabledBorder: enabledBorder,
),
),
);
expect(getBorder(tester), enabledBorder);
await tester.pumpWidget(
buildInputDecorator(
isFocused: true,
decoration: const InputDecoration(
// errorText: null (default)
// enabled: true (default)
errorBorder: errorBorder,
focusedBorder: focusedBorder,
focusedErrorBorder: focusedErrorBorder,
disabledBorder: disabledBorder,
enabledBorder: enabledBorder,
),
),
);
await tester.pumpAndSettle(); // border changes are animated
expect(getBorder(tester), focusedBorder);
await tester.pumpWidget(
buildInputDecorator(
isFocused: true,
decoration: const InputDecoration(
errorText: 'error',
// enabled: true (default)
errorBorder: errorBorder,
focusedBorder: focusedBorder,
focusedErrorBorder: focusedErrorBorder,
disabledBorder: disabledBorder,
enabledBorder: enabledBorder,
),
),
);
await tester.pumpAndSettle(); // border changes are animated
expect(getBorder(tester), focusedErrorBorder);
await tester.pumpWidget(
buildInputDecorator(
// isFocused: false (default)
decoration: const InputDecoration(
errorText: 'error',
// enabled: true (default)
errorBorder: errorBorder,
focusedBorder: focusedBorder,
focusedErrorBorder: focusedErrorBorder,
disabledBorder: disabledBorder,
enabledBorder: enabledBorder,
),
),
);
await tester.pumpAndSettle(); // border changes are animated
expect(getBorder(tester), errorBorder);
await tester.pumpWidget(
buildInputDecorator(
// isFocused: false (default)
decoration: const InputDecoration(
errorText: 'error',
enabled: false,
errorBorder: errorBorder,
focusedBorder: focusedBorder,
focusedErrorBorder: focusedErrorBorder,
disabledBorder: disabledBorder,
enabledBorder: enabledBorder,
),
),
);
await tester.pumpAndSettle(); // border changes are animated
expect(getBorder(tester), errorBorder);
await tester.pumpWidget(
buildInputDecorator(
// isFocused: false (default)
decoration: const InputDecoration(
// errorText: false (default)
enabled: false,
errorBorder: errorBorder,
focusedBorder: focusedBorder,
focusedErrorBorder: focusedErrorBorder,
disabledBorder: disabledBorder,
enabledBorder: enabledBorder,
),
),
);
await tester.pumpAndSettle(); // border changes are animated
expect(getBorder(tester), disabledBorder);
await tester.pumpWidget(
buildInputDecorator(
isFocused: true,
decoration: const InputDecoration(
// errorText: null (default)
enabled: false,
errorBorder: errorBorder,
focusedBorder: focusedBorder,
focusedErrorBorder: focusedErrorBorder,
disabledBorder: disabledBorder,
enabledBorder: enabledBorder,
),
),
);
await tester.pumpAndSettle(); // border changes are animated
expect(getBorder(tester), disabledBorder);
});
}