Unverified Commit 79d32877 authored by xubaolin's avatar xubaolin Committed by GitHub

fix the DropdownButtonFormField's label display bug when the `hint` is non-null (#87104)

parent fe52e566
......@@ -1650,6 +1650,18 @@ class DropdownButtonFormField<T> extends FormField<T> {
final InputDecoration effectiveDecoration = decorationArg.applyDefaults(
Theme.of(field.context).inputDecorationTheme,
);
final bool showSelectedItem = items != null && items.where((DropdownMenuItem<T> item) => item.value == state.value).isNotEmpty;
bool isHintOrDisabledHintAvailable() {
final bool isDropdownDisabled = onChanged == null || (items == null || items.isEmpty);
if (isDropdownDisabled) {
return hint != null || disabledHint != null;
} else {
return hint != null;
}
}
final bool isEmpty = !showSelectedItem && !isHintOrDisabledHintAvailable();
// An unfocusable Focus widget so that this widget can detect if its
// descendants have focus or not.
return Focus(
......@@ -1658,7 +1670,7 @@ class DropdownButtonFormField<T> extends FormField<T> {
child: Builder(builder: (BuildContext context) {
return InputDecorator(
decoration: effectiveDecoration.copyWith(errorText: field.errorText),
isEmpty: items == null || items.where((DropdownMenuItem<T> item) => item.value == state.value).isEmpty,
isEmpty: isEmpty,
isFocused: Focus.of(context).hasFocus,
child: DropdownButtonHideUnderline(
child: DropdownButton<T>(
......
......@@ -149,6 +149,248 @@ void verifyPaintedShadow(Finder customPaint, int elevation) {
}
void main() {
// Regression test for https://github.com/flutter/flutter/issues/87102
testWidgets('label position test - show hint', (WidgetTester tester) async {
int? value;
await tester.pumpWidget(
TestApp(
textDirection: TextDirection.ltr,
child: Material(
child: DropdownButtonFormField<int?>(
decoration: const InputDecoration(
labelText: 'labelText',
),
value: value,
hint: const Text('Hint'),
onChanged: (int? newValue) {
value = newValue;
},
items: const <DropdownMenuItem<int?>>[
DropdownMenuItem<int?>(
value: 1,
child: Text('One'),
),
DropdownMenuItem<int?>(
value: 2,
child: Text('Two'),
),
DropdownMenuItem<int?>(
value: 3,
child: Text('Three'),
),
],
),
),
),
);
expect(value, null);
final Offset hintEmptyLabel = tester.getTopLeft(find.text('labelText'));
// Select a item.
await tester.tap(find.text('Hint'), warnIfMissed: false);
await tester.pumpAndSettle();
await tester.tap(find.text('One').last);
await tester.pumpAndSettle();
expect(value, 1);
final Offset oneValueLabel = tester.getTopLeft(find.text('labelText'));
// The position of the label does not change.
expect(hintEmptyLabel, oneValueLabel);
});
testWidgets('label position test - show disabledHint: disable', (WidgetTester tester) async {
int? value;
await tester.pumpWidget(
TestApp(
textDirection: TextDirection.ltr,
child: Material(
child: DropdownButtonFormField<int?>(
decoration: const InputDecoration(
labelText: 'labelText',
),
value: value,
disabledHint: const Text('disabledHint'),
onChanged: null, // disable the menu to show the disabledHint.
items: const <DropdownMenuItem<int?>>[
DropdownMenuItem<int?>(
value: 1,
child: Text('One'),
),
DropdownMenuItem<int?>(
value: 2,
child: Text('Two'),
),
DropdownMenuItem<int?>(
value: 3,
child: Text('Three'),
),
],
),
),
),
);
expect(value, null); // disabledHint shown.
final Offset hintEmptyLabel = tester.getTopLeft(find.text('labelText'));
expect(hintEmptyLabel, const Offset(0.0, 12.0));
});
testWidgets('label position test - show disabledHint: enable + null item', (WidgetTester tester) async {
int? value;
await tester.pumpWidget(
TestApp(
textDirection: TextDirection.ltr,
child: Material(
child: DropdownButtonFormField<int?>(
decoration: const InputDecoration(
labelText: 'labelText',
),
value: value,
disabledHint: const Text('disabledHint'),
onChanged: (_) {},
items: null,
),
),
),
);
expect(value, null); // disabledHint shown.
final Offset hintEmptyLabel = tester.getTopLeft(find.text('labelText'));
expect(hintEmptyLabel, const Offset(0.0, 12.0));
});
testWidgets('label position test - show disabledHint: enable + empty item', (WidgetTester tester) async {
int? value;
await tester.pumpWidget(
TestApp(
textDirection: TextDirection.ltr,
child: Material(
child: DropdownButtonFormField<int?>(
decoration: const InputDecoration(
labelText: 'labelText',
),
value: value,
disabledHint: const Text('disabledHint'),
onChanged: (_) {},
items: const <DropdownMenuItem<int?>>[],
),
),
),
);
expect(value, null); // disabledHint shown.
final Offset hintEmptyLabel = tester.getTopLeft(find.text('labelText'));
expect(hintEmptyLabel, const Offset(0.0, 12.0));
});
testWidgets('label position test - show hint: enable + empty item', (WidgetTester tester) async {
int? value;
await tester.pumpWidget(
TestApp(
textDirection: TextDirection.ltr,
child: Material(
child: DropdownButtonFormField<int?>(
decoration: const InputDecoration(
labelText: 'labelText',
),
value: value,
hint: const Text('hint'),
onChanged: (_) {},
items: const <DropdownMenuItem<int?>>[],
),
),
),
);
expect(value, null); // hint shown.
final Offset hintEmptyLabel = tester.getTopLeft(find.text('labelText'));
expect(hintEmptyLabel, const Offset(0.0, 12.0));
});
testWidgets('label position test - no hint shown: enable + no selected + disabledHint', (WidgetTester tester) async {
int? value;
await tester.pumpWidget(
TestApp(
textDirection: TextDirection.ltr,
child: Material(
child: DropdownButtonFormField<int?>(
decoration: const InputDecoration(
labelText: 'labelText',
),
value: value,
disabledHint: const Text('disabledHint'),
onChanged: (_) {},
items: const <DropdownMenuItem<int?>>[
DropdownMenuItem<int?>(
value: 1,
child: Text('One'),
),
DropdownMenuItem<int?>(
value: 2,
child: Text('Two'),
),
DropdownMenuItem<int?>(
value: 3,
child: Text('Three'),
),
],
),
),
),
);
expect(value, null);
final Offset hintEmptyLabel = tester.getTopLeft(find.text('labelText'));
expect(hintEmptyLabel, const Offset(0.0, 24.0));
});
testWidgets('label position test - show selected item: disabled + hint + disabledHint', (WidgetTester tester) async {
const int value = 1;
await tester.pumpWidget(
TestApp(
textDirection: TextDirection.ltr,
child: Material(
child: DropdownButtonFormField<int?>(
decoration: const InputDecoration(
labelText: 'labelText',
),
value: value,
hint: const Text('hint'),
disabledHint: const Text('disabledHint'),
onChanged: null, // disabled
items: const <DropdownMenuItem<int?>>[
DropdownMenuItem<int?>(
value: 1,
child: Text('One'),
),
DropdownMenuItem<int?>(
value: 2,
child: Text('Two'),
),
DropdownMenuItem<int?>(
value: 3,
child: Text('Three'),
),
],
),
),
),
);
expect(value, 1);
final Offset hintEmptyLabel = tester.getTopLeft(find.text('labelText'));
expect(hintEmptyLabel, const Offset(0.0, 12.0));
});
// Regression test for https://github.com/flutter/flutter/issues/82910
testWidgets('null value test', (WidgetTester tester) async {
int? value = 1;
......@@ -181,7 +423,7 @@ void main() {
DropdownMenuItem<int?>(
value: 3,
child: Text('Three'),
)
),
],
),
),
......
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