Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Always relies on floatingLabelStyle when FloatingLabelBehavior.always #147374

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 9 additions & 9 deletions packages/flutter/lib/src/material/input_decorator.dart
Expand Up @@ -1789,8 +1789,11 @@ class InputDecorator extends StatefulWidget {
/// Whether the label needs to get out of the way of the input, either by
/// floating or disappearing.
///
/// Will withdraw when not empty, or when focused while enabled.
bool get _labelShouldWithdraw => !isEmpty || (isFocused && decoration.enabled);
/// Will withdraw when not empty, when focused while enabled, or when
/// floating behavior is [FloatingLabelBehavior.always].
bool get _labelShouldWithdraw => !isEmpty
|| (isFocused && decoration.enabled)
|| decoration.floatingLabelBehavior == FloatingLabelBehavior.always;

@override
State<InputDecorator> createState() => _InputDecoratorState();
Expand Down Expand Up @@ -1833,9 +1836,8 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
void initState() {
super.initState();

final bool labelIsInitiallyFloating = widget.decoration.floatingLabelBehavior == FloatingLabelBehavior.always
|| (widget.decoration.floatingLabelBehavior != FloatingLabelBehavior.never &&
widget._labelShouldWithdraw);
final bool labelIsInitiallyFloating = widget.decoration.floatingLabelBehavior != FloatingLabelBehavior.never
&& widget._labelShouldWithdraw;

_floatingLabelController = AnimationController(
duration: _kTransitionDuration,
Expand Down Expand Up @@ -1898,8 +1900,7 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
final bool floatBehaviorChanged = widget.decoration.floatingLabelBehavior != old.decoration.floatingLabelBehavior;

if (widget._labelShouldWithdraw != old._labelShouldWithdraw || floatBehaviorChanged) {
if (_floatingLabelEnabled
&& (widget._labelShouldWithdraw || widget.decoration.floatingLabelBehavior == FloatingLabelBehavior.always)) {
if (_floatingLabelEnabled && widget._labelShouldWithdraw) {
_floatingLabelController.forward();
} else {
_floatingLabelController.reverse();
Expand Down Expand Up @@ -1989,8 +1990,7 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
// hint would.
bool get _hasInlineLabel {
return !widget._labelShouldWithdraw
&& (decoration.labelText != null || decoration.label != null)
&& decoration.floatingLabelBehavior != FloatingLabelBehavior.always;
&& (decoration.labelText != null || decoration.label != null);
}

// If the label is a floating placeholder, it's always shown.
Expand Down
174 changes: 174 additions & 0 deletions packages/flutter/test/material/input_decorator_test.dart
Expand Up @@ -2032,6 +2032,137 @@ void main() {
});
});
});

testWidgets('floatingLabelStyle overrides default style', (WidgetTester tester) async {
const TextStyle floatingLabelStyle = TextStyle(color: Colors.indigo, fontSize: 16.0);

await tester.pumpWidget(
buildInputDecorator(
isEmpty: true,
isFocused: true, // Label appears floating above input field.
decoration: const InputDecoration(
labelText: labelText,
floatingLabelStyle: floatingLabelStyle,
),
),
);

expect(getLabelStyle(tester).color, floatingLabelStyle.color);
expect(getLabelStyle(tester).fontSize, floatingLabelStyle.fontSize);
});

testWidgets('floatingLabelStyle defaults to labelStyle', (WidgetTester tester) async {
const TextStyle labelStyle = TextStyle(color: Colors.amber, fontSize: 16.0);

await tester.pumpWidget(
buildInputDecorator(
isEmpty: true,
isFocused: true, // Label appears floating above input field.
decoration: const InputDecoration(
labelText: labelText,
labelStyle: labelStyle,
),
),
);

expect(getLabelStyle(tester).color, labelStyle.color);
expect(getLabelStyle(tester).fontSize, labelStyle.fontSize);
});

testWidgets('floatingLabelStyle takes precedence over labelStyle', (WidgetTester tester) async {
const TextStyle labelStyle = TextStyle(color: Colors.amber, fontSize: 16.0);
const TextStyle floatingLabelStyle = TextStyle(color: Colors.indigo, fontSize: 16.0);

await tester.pumpWidget(
buildInputDecorator(
isEmpty: true,
isFocused: true, // Label appears floating above input field.
decoration: const InputDecoration(
labelText: labelText,
labelStyle: labelStyle,
floatingLabelStyle: floatingLabelStyle,
),
),
);

expect(getLabelStyle(tester).color, floatingLabelStyle.color);
expect(getLabelStyle(tester).fontSize, floatingLabelStyle.fontSize);
});

testWidgets('InputDecorationTheme labelStyle overrides default style', (WidgetTester tester) async {
const TextStyle labelStyle = TextStyle(color: Colors.amber, fontSize: 16.0);

await tester.pumpWidget(
buildInputDecorator(
isEmpty: true, // Label appears inline, on top of the input field.
inputDecorationTheme: const InputDecorationTheme(
labelStyle: labelStyle,
),
decoration: const InputDecoration(
labelText: labelText,
),
),
);

expect(getLabelStyle(tester).color, labelStyle.color);
});

testWidgets('InputDecorationTheme floatingLabelStyle overrides default style', (WidgetTester tester) async {
const TextStyle floatingLabelStyle = TextStyle(color: Colors.indigo, fontSize: 16.0);

await tester.pumpWidget(
buildInputDecorator(
isEmpty: true,
isFocused: true, // Label appears floating above input field.
inputDecorationTheme: const InputDecorationTheme(
floatingLabelStyle: floatingLabelStyle,
),
decoration: const InputDecoration(
labelText: labelText,
),
),
);

expect(getLabelStyle(tester).color, floatingLabelStyle.color);
});

testWidgets('floatingLabelStyle is always used when FloatingLabelBehavior.always', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/147231.
const TextStyle labelStyle = TextStyle(color: Colors.amber, fontSize: 16.0);
const TextStyle floatingLabelStyle = TextStyle(color: Colors.indigo, fontSize: 16.0);

await tester.pumpWidget(
buildInputDecorator(
isEmpty: true,
decoration: const InputDecoration(
labelText: labelText,
labelStyle: labelStyle,
floatingLabelStyle: floatingLabelStyle,
floatingLabelBehavior: FloatingLabelBehavior.always,
),
),
);

expect(getLabelStyle(tester).color, floatingLabelStyle.color);
expect(getLabelStyle(tester).fontSize, floatingLabelStyle.fontSize);

// Focus the input decorator.
await tester.pumpWidget(
buildInputDecorator(
isEmpty: true,
isFocused: true,
decoration: const InputDecoration(
labelText: labelText,
labelStyle: labelStyle,
floatingLabelStyle: floatingLabelStyle,
floatingLabelBehavior: FloatingLabelBehavior.always,
),
),
);

expect(getLabelStyle(tester).color, floatingLabelStyle.color);
expect(getLabelStyle(tester).fontSize, floatingLabelStyle.fontSize);
});
});

group('Material3 - InputDecoration labelText layout', () {
Expand Down Expand Up @@ -4915,6 +5046,49 @@ void main() {
expect(getOpacity(tester, prefixText), 1.0);
});

testWidgets('Prefix and suffix are not visible when decorator is empty', (WidgetTester tester) async {
const String prefixText = 'Prefix';
const String suffixText = 'Suffix';

await tester.pumpWidget(
buildInputDecorator(
isEmpty: true,
decoration: const InputDecoration(
filled: true,
labelText: labelText,
prefixText: prefixText,
suffixText: suffixText,
),
),
);

// Prefix and suffix are hidden.
expect(getOpacity(tester, prefixText), 0.0);
expect(getOpacity(tester, suffixText), 0.0);
});

testWidgets('Prefix and suffix are visible when decorator is empty and floating behavior is FloatingBehavior.always', (WidgetTester tester) async {
const String prefixText = 'Prefix';
const String suffixText = 'Suffix';

await tester.pumpWidget(
buildInputDecorator(
isEmpty: true,
decoration: const InputDecoration(
filled: true,
labelText: labelText,
prefixText: prefixText,
suffixText: suffixText,
floatingLabelBehavior: FloatingLabelBehavior.always,
),
),
);

// Prefix and suffix are visible.
expect(getOpacity(tester, prefixText), 1.0);
expect(getOpacity(tester, suffixText), 1.0);
});

testWidgets('OutlineInputBorder and InputDecorator long labels and in Floating, the width should ignore the icon width', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/64427.
const String labelText = 'Flutter is Google’s UI toolkit for building beautiful, natively compiled applications for mobile, web, and desktop from a single codebase.';
Expand Down