Fix DropdownMenu default width does not take label into account (#161219)
## Description This PR fixes `DropdownMenu` default width when a long label is provided. Before: The width is based on the longest menu item (which can be smaller than the label):  After: The width also depends on the label width when it is longer than the menu items.  ## Related Issue Fixes [DropdownMenu default width does not take label into account](https://github.com/flutter/flutter/issues/136678) ## Tests Adds 2 tests.
This commit is contained in:
parent
60d0bfcca4
commit
b61335bd3b
@ -1079,11 +1079,24 @@ class _DropdownMenuState<T> extends State<DropdownMenu<T>> {
|
||||
? textField
|
||||
: _DropdownMenuBody(
|
||||
width: widget.width,
|
||||
// The children, except the text field, are used to compute the preferred width,
|
||||
// which is the width of the longest children, plus the width of trailingButton
|
||||
// and leadingButton.
|
||||
//
|
||||
// See _RenderDropdownMenuBody layout logic.
|
||||
children: <Widget>[
|
||||
textField,
|
||||
..._initialMenu!.map(
|
||||
(Widget item) => ExcludeFocus(excluding: !controller.isOpen, child: item),
|
||||
),
|
||||
if (widget.label != null)
|
||||
ExcludeSemantics(
|
||||
child: Padding(
|
||||
// See RenderEditable.floatingCursorAddedMargin for the default horizontal padding.
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4.0),
|
||||
child: DefaultTextStyle(style: effectiveTextStyle!, child: widget.label!),
|
||||
),
|
||||
),
|
||||
trailingButton,
|
||||
leadingButton,
|
||||
],
|
||||
@ -1317,9 +1330,11 @@ class _RenderDropdownMenuBody extends RenderBox
|
||||
continue;
|
||||
}
|
||||
final double maxIntrinsicWidth = child.getMinIntrinsicWidth(height);
|
||||
// Add the width of leading icon.
|
||||
if (child == lastChild) {
|
||||
width += maxIntrinsicWidth;
|
||||
}
|
||||
// Add the width of trailing icon.
|
||||
if (child == childBefore(lastChild!)) {
|
||||
width += maxIntrinsicWidth;
|
||||
}
|
||||
@ -1344,11 +1359,11 @@ class _RenderDropdownMenuBody extends RenderBox
|
||||
continue;
|
||||
}
|
||||
final double maxIntrinsicWidth = child.getMaxIntrinsicWidth(height);
|
||||
// Add the width of leading Icon.
|
||||
// Add the width of leading icon.
|
||||
if (child == lastChild) {
|
||||
width += maxIntrinsicWidth;
|
||||
}
|
||||
// Add the width of trailing Icon.
|
||||
// Add the width of trailing icon.
|
||||
if (child == childBefore(lastChild!)) {
|
||||
width += maxIntrinsicWidth;
|
||||
}
|
||||
|
@ -718,6 +718,64 @@ void main() {
|
||||
expect(box.size.width, customWidth);
|
||||
});
|
||||
|
||||
testWidgets('The width is determined by the menu entries', (WidgetTester tester) async {
|
||||
const double entryLabelWidth = 100;
|
||||
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: Scaffold(
|
||||
body: DropdownMenu<int>(
|
||||
dropdownMenuEntries: <DropdownMenuEntry<int>>[
|
||||
DropdownMenuEntry<int>(
|
||||
value: 0,
|
||||
label: 'Flutter',
|
||||
labelWidget: SizedBox(width: entryLabelWidth),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final double width = tester.getSize(find.byType(DropdownMenu<int>)).width;
|
||||
const double menuEntryPadding = 24.0; // See _kDefaultHorizontalPadding.
|
||||
const double leadingWidth = 16.0;
|
||||
const double trailingWidth = 56.0;
|
||||
|
||||
expect(width, entryLabelWidth + leadingWidth + trailingWidth + menuEntryPadding);
|
||||
});
|
||||
|
||||
testWidgets('The width is determined by the label when it is longer than menu entries', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
const double labelWidth = 120;
|
||||
const double entryLabelWidth = 100;
|
||||
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: Scaffold(
|
||||
body: DropdownMenu<int>(
|
||||
label: SizedBox(width: labelWidth),
|
||||
dropdownMenuEntries: <DropdownMenuEntry<int>>[
|
||||
DropdownMenuEntry<int>(
|
||||
value: 0,
|
||||
label: 'Flutter',
|
||||
labelWidget: SizedBox(width: entryLabelWidth),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final double width = tester.getSize(find.byType(DropdownMenu<int>)).width;
|
||||
const double leadingWidth = 16.0;
|
||||
const double trailingWidth = 56.0;
|
||||
const double labelPadding = 8.0; // See RenderEditable.floatingCursorAddedMargin.
|
||||
|
||||
expect(width, labelWidth + labelPadding + leadingWidth + trailingWidth);
|
||||
});
|
||||
|
||||
testWidgets('The width of MenuAnchor respects MenuAnchor.expandedInsets', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
@ -962,7 +1020,7 @@ void main() {
|
||||
// Default text field (without leading icon).
|
||||
await tester.pumpWidget(buildTest(themeData, menuChildren, label: const Text('label')));
|
||||
|
||||
final Finder label = find.text('label');
|
||||
final Finder label = find.text('label').first;
|
||||
final Offset labelTopLeft = tester.getTopLeft(label);
|
||||
|
||||
await tester.tap(find.byType(DropdownMenu<TestMenu>));
|
||||
@ -985,7 +1043,7 @@ void main() {
|
||||
|
||||
final Finder leadingIcon = find.widgetWithIcon(SizedBox, Icons.search).last;
|
||||
final double iconWidth = tester.getSize(leadingIcon).width;
|
||||
final Finder updatedLabel = find.text('label');
|
||||
final Finder updatedLabel = find.text('label').first;
|
||||
final Offset updatedLabelTopLeft = tester.getTopLeft(updatedLabel);
|
||||
|
||||
await tester.tap(find.byType(DropdownMenu<TestMenu>));
|
||||
@ -1009,7 +1067,7 @@ void main() {
|
||||
|
||||
final Finder largeLeadingIcon = find.widgetWithIcon(SizedBox, Icons.search).last;
|
||||
final double largeIconWidth = tester.getSize(largeLeadingIcon).width;
|
||||
final Finder updatedLabel1 = find.text('label');
|
||||
final Finder updatedLabel1 = find.text('label').first;
|
||||
final Offset updatedLabelTopLeft1 = tester.getTopLeft(updatedLabel1);
|
||||
|
||||
await tester.tap(find.byType(DropdownMenu<TestMenu>));
|
||||
@ -1040,7 +1098,7 @@ void main() {
|
||||
),
|
||||
);
|
||||
|
||||
final Finder label = find.text('label');
|
||||
final Finder label = find.text('label').first;
|
||||
final Offset labelTopRight = tester.getTopRight(label);
|
||||
|
||||
await tester.tap(find.byType(DropdownMenu<TestMenu>));
|
||||
@ -1072,7 +1130,7 @@ void main() {
|
||||
final Finder leadingIcon = find.widgetWithIcon(SizedBox, Icons.search).last;
|
||||
final double iconWidth = tester.getSize(leadingIcon).width;
|
||||
final Offset dropdownMenuTopRight = tester.getTopRight(find.byType(DropdownMenu<TestMenu>));
|
||||
final Finder updatedLabel = find.text('label');
|
||||
final Finder updatedLabel = find.text('label').first;
|
||||
final Offset updatedLabelTopRight = tester.getTopRight(updatedLabel);
|
||||
|
||||
await tester.tap(find.byType(DropdownMenu<TestMenu>));
|
||||
@ -1110,7 +1168,7 @@ void main() {
|
||||
final Offset updatedDropdownMenuTopRight = tester.getTopRight(
|
||||
find.byType(DropdownMenu<TestMenu>),
|
||||
);
|
||||
final Finder updatedLabel1 = find.text('label');
|
||||
final Finder updatedLabel1 = find.text('label').first;
|
||||
final Offset updatedLabelTopRight1 = tester.getTopRight(updatedLabel1);
|
||||
|
||||
await tester.tap(find.byType(DropdownMenu<TestMenu>));
|
||||
|
Loading…
x
Reference in New Issue
Block a user