[Material] Add API for an unpainted input border (#21289)
* Introduce a rounded InputBorder with no paint * Update documentation for API * Change name of Widget to NoStrokeInputBorder and updated documentation * [FilledInputBorder] PR feedback. * [FilledInputBorder] typo correction. * [FilledInputBorder] Removing news. * [FilledInputBorder] PR feedback. * [FilledInputBorder] Removing use of borderSide. * [FilledInputBorder] Adding tests for hashcode. * [FilledInputBorder] Comments. * [TextFields] Input decoration feature parity. * [TextFields] Making floating of placeholder optional. * [TextFields] Cleanup * [TextFields] Removing unused isAnimated. * [TextFields] Cleanup. * [TextFields] Correcting border. * [TextFields] Correcting comment. * [TextFields] Comment. * [TextFields] Corrections for tests. * [TextFields] Cleanup. * [TextFields] Cleanup. * [TextFields] Tests. * [TextFields] Cleanup. * [TextFields] Cleanup. * [TextFields] Formatting. * [TextFields] PR feedback. * [TextFields] PR feedback. * [TextFields] PR feedback.
This commit is contained in:
@@ -139,7 +139,7 @@ class UnderlineInputBorder extends InputBorder {
|
||||
/// and right corners have a circular radius of 4.0. The [borderRadius]
|
||||
/// parameter must not be null.
|
||||
const UnderlineInputBorder({
|
||||
BorderSide borderSide = BorderSide.none,
|
||||
BorderSide borderSide = const BorderSide(),
|
||||
this.borderRadius = const BorderRadius.only(
|
||||
topLeft: Radius.circular(4.0),
|
||||
topRight: Radius.circular(4.0),
|
||||
@@ -256,17 +256,26 @@ class UnderlineInputBorder extends InputBorder {
|
||||
class OutlineInputBorder extends InputBorder {
|
||||
/// Creates a rounded rectangle outline border for an [InputDecorator].
|
||||
///
|
||||
/// The [borderSide] parameter defaults to [BorderSide.none] (it must not be
|
||||
/// null). Applications typically do not specify a [borderSide] parameter
|
||||
/// because the input decorator substitutes its own, using [copyWith], based
|
||||
/// on the current theme and [InputDecorator.isFocused].
|
||||
/// If the [borderSide] parameter is [BorderSide.none], it will not draw a
|
||||
/// border. However, it will still define a shape (which you can see if
|
||||
/// [InputDecoration.filled] is true).
|
||||
///
|
||||
/// If an application does not specify a [borderSide] parameter of
|
||||
/// value [BorderSide.none], the input decorator substitutes its own, using
|
||||
/// [copyWith], based on the current theme and [InputDecorator.isFocused].
|
||||
///
|
||||
/// The [borderRadius] parameter defaults to a value where all four
|
||||
/// corners have a circular radius of 4.0. The [borderRadius] parameter
|
||||
/// must not be null and the corner radii must be circular, i.e. their
|
||||
/// [Radius.x] and [Radius.y] values must be the same.
|
||||
///
|
||||
/// See also:
|
||||
/// * [InputDecoration.hasFloatingPlaceholder], which should be set to false
|
||||
/// when the [borderSide] is [BorderSide.none]. If let as true, the label
|
||||
/// will extend beyond the container as if the border were still being
|
||||
/// drawn.
|
||||
const OutlineInputBorder({
|
||||
BorderSide borderSide = BorderSide.none,
|
||||
BorderSide borderSide = const BorderSide(),
|
||||
this.borderRadius = const BorderRadius.all(Radius.circular(4.0)),
|
||||
this.gapPadding = 4.0,
|
||||
}) : assert(borderRadius != null),
|
||||
|
||||
@@ -1488,7 +1488,9 @@ class InputDecorator extends StatefulWidget {
|
||||
/// Typically an [EditableText], [DropdownButton], or [InkWell].
|
||||
final Widget child;
|
||||
|
||||
bool get _labelIsFloating => !isEmpty || isFocused;
|
||||
/// Whether the label needs to get out of the way of the input, either by
|
||||
/// floating or disappearing.
|
||||
bool get _labelShouldWithdraw => !isEmpty || isFocused;
|
||||
|
||||
@override
|
||||
_InputDecoratorState createState() => _InputDecoratorState();
|
||||
@@ -1526,7 +1528,7 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
|
||||
_floatingLabelController = AnimationController(
|
||||
duration: _kTransitionDuration,
|
||||
vsync: this,
|
||||
value: widget._labelIsFloating ? 1.0 : 0.0,
|
||||
value: (widget.decoration.hasFloatingPlaceholder && widget._labelShouldWithdraw) ? 1.0 : 0.0,
|
||||
);
|
||||
_floatingLabelController.addListener(_handleChange);
|
||||
|
||||
@@ -1573,9 +1575,10 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
|
||||
if (widget.decoration != old.decoration)
|
||||
_effectiveDecoration = null;
|
||||
|
||||
if (widget._labelIsFloating != old._labelIsFloating) {
|
||||
if (widget._labelIsFloating)
|
||||
if (widget._labelShouldWithdraw != old._labelShouldWithdraw && widget.decoration.hasFloatingPlaceholder) {
|
||||
if (widget._labelShouldWithdraw) {
|
||||
_floatingLabelController.forward();
|
||||
}
|
||||
else
|
||||
_floatingLabelController.reverse();
|
||||
}
|
||||
@@ -1641,7 +1644,11 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
|
||||
// True if the label will be shown and the hint will not.
|
||||
// If we're not focused, there's no value, and labelText was provided,
|
||||
// then the label appears where the hint would.
|
||||
bool get _hasInlineLabel => !isFocused && isEmpty && decoration.labelText != null;
|
||||
bool get _hasInlineLabel => !widget._labelShouldWithdraw && decoration.labelText != null;
|
||||
|
||||
// If the label is a floating placeholder, it's always shown.
|
||||
bool get _shouldShowLabel => _hasInlineLabel || decoration.hasFloatingPlaceholder;
|
||||
|
||||
|
||||
// The base style for the inline label or hint when they're displayed "inline",
|
||||
// i.e. when they appear in place of the empty text field.
|
||||
@@ -1671,6 +1678,10 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
|
||||
}
|
||||
|
||||
InputBorder _getDefaultBorder(ThemeData themeData) {
|
||||
if (decoration.border?.borderSide == BorderSide.none) {
|
||||
return decoration.border;
|
||||
}
|
||||
|
||||
Color borderColor;
|
||||
if (decoration.enabled) {
|
||||
borderColor = decoration.errorText == null
|
||||
@@ -1731,23 +1742,28 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
|
||||
final TextStyle inlineLabelStyle = inlineStyle.merge(decoration.labelStyle);
|
||||
final Widget label = decoration.labelText == null ? null : _Shaker(
|
||||
animation: _shakingLabelController.view,
|
||||
child: AnimatedDefaultTextStyle(
|
||||
child: AnimatedOpacity(
|
||||
duration: _kTransitionDuration,
|
||||
curve: _kTransitionCurve,
|
||||
style: widget._labelIsFloating
|
||||
? _getFloatingLabelStyle(themeData)
|
||||
: inlineLabelStyle,
|
||||
child: Text(
|
||||
decoration.labelText,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
textAlign: textAlign,
|
||||
opacity: _shouldShowLabel ? 1.0 : 0.0,
|
||||
child: AnimatedDefaultTextStyle(
|
||||
duration:_kTransitionDuration,
|
||||
curve: _kTransitionCurve,
|
||||
style: widget._labelShouldWithdraw
|
||||
? _getFloatingLabelStyle(themeData)
|
||||
: inlineLabelStyle,
|
||||
child: Text(
|
||||
decoration.labelText,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
textAlign: textAlign,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final Widget prefix = decoration.prefix == null && decoration.prefixText == null ? null :
|
||||
_AffixText(
|
||||
labelIsFloating: widget._labelIsFloating,
|
||||
labelIsFloating: widget._labelShouldWithdraw,
|
||||
text: decoration.prefixText,
|
||||
style: decoration.prefixStyle ?? hintStyle,
|
||||
child: decoration.prefix,
|
||||
@@ -1755,7 +1771,7 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
|
||||
|
||||
final Widget suffix = decoration.suffix == null && decoration.suffixText == null ? null :
|
||||
_AffixText(
|
||||
labelIsFloating: widget._labelIsFloating,
|
||||
labelIsFloating: widget._labelShouldWithdraw,
|
||||
text: decoration.suffixText,
|
||||
style: decoration.suffixStyle ?? hintStyle,
|
||||
child: decoration.suffix,
|
||||
@@ -1931,6 +1947,7 @@ class InputDecoration {
|
||||
this.errorText,
|
||||
this.errorStyle,
|
||||
this.errorMaxLines,
|
||||
this.hasFloatingPlaceholder = true,
|
||||
this.isDense,
|
||||
this.contentPadding,
|
||||
this.prefixIcon,
|
||||
@@ -1965,6 +1982,7 @@ class InputDecoration {
|
||||
/// Sets the [isCollapsed] property to true.
|
||||
const InputDecoration.collapsed({
|
||||
@required this.hintText,
|
||||
this.hasFloatingPlaceholder = true,
|
||||
this.hintStyle,
|
||||
this.filled = false,
|
||||
this.fillColor,
|
||||
@@ -2088,6 +2106,16 @@ class InputDecoration {
|
||||
/// of the [Text] widget used to display the error.
|
||||
final int errorMaxLines;
|
||||
|
||||
/// Whether the label floats on focus.
|
||||
///
|
||||
/// If this is false, the placeholder disappears when the input has focus or
|
||||
/// inputted text.
|
||||
/// If this is true, the placeholder will rise to the top of the input when
|
||||
/// the input has focus or inputted text.
|
||||
///
|
||||
/// Defaults to true.
|
||||
final bool hasFloatingPlaceholder;
|
||||
|
||||
/// Whether the input [child] is part of a dense form (i.e., uses less vertical
|
||||
/// space).
|
||||
///
|
||||
@@ -2424,6 +2452,7 @@ class InputDecoration {
|
||||
String errorText,
|
||||
TextStyle errorStyle,
|
||||
int errorMaxLines,
|
||||
bool hasFloatingPlaceholder,
|
||||
bool isDense,
|
||||
EdgeInsetsGeometry contentPadding,
|
||||
Widget prefixIcon,
|
||||
@@ -2458,6 +2487,7 @@ class InputDecoration {
|
||||
errorText: errorText ?? this.errorText,
|
||||
errorStyle: errorStyle ?? this.errorStyle,
|
||||
errorMaxLines: errorMaxLines ?? this.errorMaxLines,
|
||||
hasFloatingPlaceholder: hasFloatingPlaceholder ?? this.hasFloatingPlaceholder,
|
||||
isDense: isDense ?? this.isDense,
|
||||
contentPadding: contentPadding ?? this.contentPadding,
|
||||
prefixIcon: prefixIcon ?? this.prefixIcon,
|
||||
@@ -2495,6 +2525,7 @@ class InputDecoration {
|
||||
hintStyle: hintStyle ?? theme.hintStyle,
|
||||
errorStyle: errorStyle ?? theme.errorStyle,
|
||||
errorMaxLines: errorMaxLines ?? theme.errorMaxLines,
|
||||
hasFloatingPlaceholder: hasFloatingPlaceholder ?? theme.hasFloatingPlaceholder,
|
||||
isDense: isDense ?? theme.isDense,
|
||||
contentPadding: contentPadding ?? theme.contentPadding,
|
||||
prefixStyle: prefixStyle ?? theme.prefixStyle,
|
||||
@@ -2528,6 +2559,7 @@ class InputDecoration {
|
||||
&& typedOther.errorText == errorText
|
||||
&& typedOther.errorStyle == errorStyle
|
||||
&& typedOther.errorMaxLines == errorMaxLines
|
||||
&& typedOther.hasFloatingPlaceholder == hasFloatingPlaceholder
|
||||
&& typedOther.isDense == isDense
|
||||
&& typedOther.contentPadding == contentPadding
|
||||
&& typedOther.isCollapsed == isCollapsed
|
||||
@@ -2568,6 +2600,7 @@ class InputDecoration {
|
||||
errorText,
|
||||
errorStyle,
|
||||
errorMaxLines,
|
||||
hasFloatingPlaceholder,
|
||||
isDense,
|
||||
hashValues(
|
||||
contentPadding,
|
||||
@@ -2619,6 +2652,8 @@ class InputDecoration {
|
||||
description.add('errorStyle: "$errorStyle"');
|
||||
if (errorMaxLines != null)
|
||||
description.add('errorMaxLines: "$errorMaxLines"');
|
||||
if (hasFloatingPlaceholder == false)
|
||||
description.add('hasFloatingPlaceholder: false');
|
||||
if (isDense ?? false)
|
||||
description.add('isDense: $isDense');
|
||||
if (contentPadding != null)
|
||||
@@ -2691,6 +2726,7 @@ class InputDecorationTheme extends Diagnosticable {
|
||||
this.hintStyle,
|
||||
this.errorStyle,
|
||||
this.errorMaxLines,
|
||||
this.hasFloatingPlaceholder = true,
|
||||
this.isDense = false,
|
||||
this.contentPadding,
|
||||
this.isCollapsed = false,
|
||||
@@ -2747,6 +2783,16 @@ class InputDecorationTheme extends Diagnosticable {
|
||||
/// of the [Text] widget used to display the error.
|
||||
final int errorMaxLines;
|
||||
|
||||
/// Whether the placeholder text floats to become a label on focus.
|
||||
///
|
||||
/// If this is false, the placeholder disappears when the input has focus or
|
||||
/// inputted text.
|
||||
/// If this is true, the placeholder will rise to the top of the input when
|
||||
/// the input has focus or inputted text.
|
||||
///
|
||||
/// Defaults to true.
|
||||
final bool hasFloatingPlaceholder;
|
||||
|
||||
/// Whether the input decorator's child is part of a dense form (i.e., uses
|
||||
/// less vertical space).
|
||||
///
|
||||
@@ -2965,6 +3011,7 @@ class InputDecorationTheme extends Diagnosticable {
|
||||
properties.add(DiagnosticsProperty<TextStyle>('hintStyle', hintStyle, defaultValue: defaultTheme.hintStyle));
|
||||
properties.add(DiagnosticsProperty<TextStyle>('errorStyle', errorStyle, defaultValue: defaultTheme.errorStyle));
|
||||
properties.add(DiagnosticsProperty<int>('errorMaxLines', errorMaxLines, defaultValue: defaultTheme.errorMaxLines));
|
||||
properties.add(DiagnosticsProperty<bool>('hasFloatingPlaceholder', hasFloatingPlaceholder, defaultValue: defaultTheme.hasFloatingPlaceholder));
|
||||
properties.add(DiagnosticsProperty<bool>('isDense', isDense, defaultValue: defaultTheme.isDense));
|
||||
properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('contentPadding', contentPadding, defaultValue: defaultTheme.contentPadding));
|
||||
properties.add(DiagnosticsProperty<bool>('isCollapsed', isCollapsed, defaultValue: defaultTheme.isCollapsed));
|
||||
|
||||
@@ -81,10 +81,10 @@ double getBorderWeight(WidgetTester tester) => getBorderSide(tester)?.width;
|
||||
|
||||
Color getBorderColor(WidgetTester tester) => getBorderSide(tester)?.color;
|
||||
|
||||
double getHintOpacity(WidgetTester tester) {
|
||||
double getOpacity(WidgetTester tester, String textValue) {
|
||||
final FadeTransition opacityWidget = tester.widget<FadeTransition>(
|
||||
find.ancestor(
|
||||
of: find.text('hint'),
|
||||
of: find.text(textValue),
|
||||
matching: find.byType(FadeTransition),
|
||||
).first
|
||||
);
|
||||
@@ -304,7 +304,7 @@ void main() {
|
||||
expect(tester.getBottomLeft(find.text('text')).dy, 44.0);
|
||||
expect(tester.getTopLeft(find.text('label')).dy, 20.0);
|
||||
expect(tester.getBottomLeft(find.text('label')).dy, 36.0);
|
||||
expect(getHintOpacity(tester), 0.0);
|
||||
expect(getOpacity(tester, 'hint'), 0.0);
|
||||
expect(getBorderBottom(tester), 56.0);
|
||||
expect(getBorderWeight(tester), 1.0);
|
||||
|
||||
@@ -324,10 +324,10 @@ void main() {
|
||||
// The animation's duration is 200ms.
|
||||
{
|
||||
await tester.pump(const Duration(milliseconds: 50));
|
||||
final double hintOpacity50ms = getHintOpacity(tester);
|
||||
final double hintOpacity50ms = getOpacity(tester, 'hint');
|
||||
expect(hintOpacity50ms, inExclusiveRange(0.0, 1.0));
|
||||
await tester.pump(const Duration(milliseconds: 50));
|
||||
final double hintOpacity100ms = getHintOpacity(tester);
|
||||
final double hintOpacity100ms = getOpacity(tester, 'hint');
|
||||
expect(hintOpacity100ms, inExclusiveRange(hintOpacity50ms, 1.0));
|
||||
}
|
||||
|
||||
@@ -339,7 +339,7 @@ void main() {
|
||||
expect(tester.getBottomLeft(find.text('label')).dy, 24.0);
|
||||
expect(tester.getTopLeft(find.text('hint')).dy, 28.0);
|
||||
expect(tester.getBottomLeft(find.text('hint')).dy, 44.0);
|
||||
expect(getHintOpacity(tester), 1.0);
|
||||
expect(getOpacity(tester, 'hint'), 1.0);
|
||||
expect(getBorderBottom(tester), 56.0);
|
||||
expect(getBorderWeight(tester), 2.0);
|
||||
|
||||
@@ -358,10 +358,10 @@ void main() {
|
||||
// The animation's duration is 200ms.
|
||||
{
|
||||
await tester.pump(const Duration(milliseconds: 50));
|
||||
final double hintOpacity50ms = getHintOpacity(tester);
|
||||
final double hintOpacity50ms = getOpacity(tester, 'hint');
|
||||
expect(hintOpacity50ms, inExclusiveRange(0.0, 1.0));
|
||||
await tester.pump(const Duration(milliseconds: 50));
|
||||
final double hintOpacity100ms = getHintOpacity(tester);
|
||||
final double hintOpacity100ms = getOpacity(tester, 'hint');
|
||||
expect(hintOpacity100ms, inExclusiveRange(0.0, hintOpacity50ms));
|
||||
}
|
||||
|
||||
@@ -373,7 +373,7 @@ void main() {
|
||||
expect(tester.getBottomLeft(find.text('label')).dy, 24.0);
|
||||
expect(tester.getTopLeft(find.text('hint')).dy, 28.0);
|
||||
expect(tester.getBottomLeft(find.text('hint')).dy, 44.0);
|
||||
expect(getHintOpacity(tester), 0.0);
|
||||
expect(getOpacity(tester, 'hint'), 0.0);
|
||||
expect(getBorderBottom(tester), 56.0);
|
||||
expect(getBorderWeight(tester), 2.0);
|
||||
});
|
||||
@@ -413,7 +413,7 @@ void main() {
|
||||
expect(tester.getBottomLeft(find.text('text')).dy, 40.0);
|
||||
expect(tester.getTopLeft(find.text('label')).dy, 16.0);
|
||||
expect(tester.getBottomLeft(find.text('label')).dy, 32.0);
|
||||
expect(getHintOpacity(tester), 0.0);
|
||||
expect(getOpacity(tester, 'hint'), 0.0);
|
||||
expect(getBorderBottom(tester), 48.0);
|
||||
expect(getBorderWeight(tester), 1.0);
|
||||
|
||||
@@ -435,7 +435,7 @@ void main() {
|
||||
expect(tester.getBottomLeft(find.text('text')).dy, 40.0);
|
||||
expect(tester.getTopLeft(find.text('label')).dy, 8.0);
|
||||
expect(tester.getBottomLeft(find.text('label')).dy, 20.0);
|
||||
expect(getHintOpacity(tester), 1.0);
|
||||
expect(getOpacity(tester, 'hint'), 1.0);
|
||||
expect(getBorderBottom(tester), 48.0);
|
||||
expect(getBorderWeight(tester), 2.0);
|
||||
});
|
||||
@@ -1167,7 +1167,7 @@ void main() {
|
||||
expect(tester.getSize(find.byType(InputDecorator)), const Size(800.0, 16.0));
|
||||
expect(tester.getSize(find.text('text')).height, 16.0);
|
||||
expect(tester.getTopLeft(find.text('text')).dy, 0.0);
|
||||
expect(getHintOpacity(tester), 0.0);
|
||||
expect(getOpacity(tester, 'hint'), 0.0);
|
||||
expect(getBorderWeight(tester), 0.0);
|
||||
|
||||
// The hint should appear
|
||||
@@ -1272,6 +1272,58 @@ void main() {
|
||||
expect(tester.getTopRight(find.text('counter')), const Offset(788.0, 64.0));
|
||||
});
|
||||
|
||||
testWidgets('InputDecoration outline shape with no border and no floating placeholder', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
buildInputDecorator(
|
||||
// isFocused: false (default)
|
||||
isEmpty: true,
|
||||
decoration: const InputDecoration(
|
||||
border: OutlineInputBorder(borderSide: BorderSide.none),
|
||||
hasFloatingPlaceholder: false,
|
||||
labelText: 'label',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// Overall height for this InputDecorator is 56dps. Layout is:
|
||||
// 20 - top padding
|
||||
// 16 - label (ahem font size 16dps)
|
||||
// 20 - bottom padding
|
||||
expect(tester.getSize(find.byType(InputDecorator)), const Size(800.0, 56.0));
|
||||
expect(tester.getTopLeft(find.text('label')).dy, 20.0);
|
||||
expect(tester.getBottomLeft(find.text('label')).dy, 36.0);
|
||||
expect(getBorderBottom(tester), 56.0);
|
||||
expect(getBorderWeight(tester), 0.0);
|
||||
});
|
||||
|
||||
testWidgets('InputDecoration outline shape with no border and no floating placeholder not empty', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
buildInputDecorator(
|
||||
// isEmpty: false (default)
|
||||
// isFocused: false (default)
|
||||
decoration: const InputDecoration(
|
||||
border: OutlineInputBorder(borderSide: BorderSide.none),
|
||||
hasFloatingPlaceholder: false,
|
||||
labelText: 'label',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// Overall height for this InputDecorator is 56dps. Layout is:
|
||||
// 20 - top padding
|
||||
// 16 - label (ahem font size 16dps)
|
||||
// 20 - bottom padding
|
||||
// expect(tester.widget<Text>(find.text('prefix')).style.color, prefixStyle.color);
|
||||
expect(tester.getSize(find.byType(InputDecorator)), const Size(800.0, 56.0));
|
||||
expect(tester.getTopLeft(find.text('label')).dy, 20.0);
|
||||
expect(tester.getBottomLeft(find.text('label')).dy, 36.0);
|
||||
expect(getBorderBottom(tester), 56.0);
|
||||
expect(getBorderWeight(tester), 0.0);
|
||||
|
||||
// The label should not be seen.
|
||||
expect(getOpacity(tester, 'label'), 0.0);
|
||||
});
|
||||
|
||||
testWidgets('InputDecorationTheme outline border', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
buildInputDecorator(
|
||||
@@ -1878,4 +1930,46 @@ void main() {
|
||||
await tester.pumpAndSettle(); // border changes are animated
|
||||
expect(getBorder(tester), disabledBorder);
|
||||
});
|
||||
|
||||
test('InputBorder equality', () {
|
||||
// OutlineInputBorder's equality is defined by the borderRadius, borderSide, & gapPadding
|
||||
const OutlineInputBorder outlineInputBorder = OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(9.0)),
|
||||
borderSide: BorderSide(color: Colors.blue),
|
||||
gapPadding: 32.0,
|
||||
);
|
||||
expect(outlineInputBorder, const OutlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.blue),
|
||||
borderRadius: BorderRadius.all(Radius.circular(9.0)),
|
||||
gapPadding: 32.0,
|
||||
));
|
||||
expect(outlineInputBorder, isNot(const OutlineInputBorder()));
|
||||
|
||||
// UnderlineInputBorder's equality is defined only by the borderSide
|
||||
const UnderlineInputBorder underlineInputBorder = UnderlineInputBorder(borderSide: BorderSide(color: Colors.blue));
|
||||
expect(underlineInputBorder, const UnderlineInputBorder(borderSide: BorderSide(color: Colors.blue)));
|
||||
expect(underlineInputBorder, isNot(const UnderlineInputBorder()));
|
||||
});
|
||||
|
||||
|
||||
test('InputBorder hashCodes', () {
|
||||
// OutlineInputBorder's hashCode is defined by the borderRadius, borderSide, & gapPadding
|
||||
const OutlineInputBorder outlineInputBorder = OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(9.0)),
|
||||
borderSide: BorderSide(color: Colors.blue),
|
||||
gapPadding: 32.0,
|
||||
);
|
||||
expect(outlineInputBorder.hashCode, const OutlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.blue),
|
||||
borderRadius: BorderRadius.all(Radius.circular(9.0)),
|
||||
gapPadding: 32.0,
|
||||
).hashCode);
|
||||
expect(outlineInputBorder.hashCode, isNot(const OutlineInputBorder().hashCode));
|
||||
|
||||
// UnderlineInputBorder's hashCode is defined only by the borderSide
|
||||
const UnderlineInputBorder underlineInputBorder = UnderlineInputBorder(borderSide: BorderSide(color: Colors.blue));
|
||||
expect(underlineInputBorder.hashCode, const UnderlineInputBorder(borderSide: BorderSide(color: Colors.blue)).hashCode);
|
||||
expect(underlineInputBorder.hashCode, isNot(const UnderlineInputBorder().hashCode));
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user