From 88fa6210ad0f36302bc700cfe5f36c4e84017a6d Mon Sep 17 00:00:00 2001 From: Tyler Holland Date: Wed, 7 Aug 2024 14:38:34 -0700 Subject: [PATCH] Allow dropdown_menu to accept any EdgeInsetsGeometry (#153053) Allow dropdown_menu to accept any EdgeInsetsGeometry instead of just strictly EdgeInsets. This follows normal Flutter widget practices when accepting a padding parameter, like Container: https://github.com/flutter/flutter/blob/main/packages/flutter/lib/src/widgets/container.dart#L307C9-L307C27 Fixes https://github.com/flutter/flutter/issues/151769 --- .../lib/src/material/dropdown_menu.dart | 17 ++++- .../test/material/dropdown_menu_test.dart | 70 +++++++++++++++++++ 2 files changed, 84 insertions(+), 3 deletions(-) diff --git a/packages/flutter/lib/src/material/dropdown_menu.dart b/packages/flutter/lib/src/material/dropdown_menu.dart index 8240f70bdf..74a9be79dd 100644 --- a/packages/flutter/lib/src/material/dropdown_menu.dart +++ b/packages/flutter/lib/src/material/dropdown_menu.dart @@ -397,7 +397,7 @@ class DropdownMenu extends StatefulWidget { /// properties are used. /// /// Defaults to null. - final EdgeInsets? expandedInsets; + final EdgeInsetsGeometry? expandedInsets; /// When [DropdownMenu.enableFilter] is true, this callback is used to /// compute the list of filtered items. @@ -884,9 +884,20 @@ class _DropdownMenuState extends State> { }, ); - if (widget.expandedInsets case final EdgeInsets padding) { + if (widget.expandedInsets case final EdgeInsetsGeometry padding) { menuAnchor = Padding( - padding: padding.copyWith(top: 0.0, bottom: 0.0), + // Clamp the top and bottom padding to 0. + padding: padding.clamp( + EdgeInsets.zero, + const EdgeInsets.only( + left: double.infinity, + right: double.infinity, + ).add(const EdgeInsetsDirectional.only( + end: double.infinity, + start: double.infinity, + ), + ), + ), child: Align( alignment: AlignmentDirectional.topStart, child: menuAnchor, diff --git a/packages/flutter/test/material/dropdown_menu_test.dart b/packages/flutter/test/material/dropdown_menu_test.dart index 913478c407..4227ac9ed2 100644 --- a/packages/flutter/test/material/dropdown_menu_test.dart +++ b/packages/flutter/test/material/dropdown_menu_test.dart @@ -352,6 +352,76 @@ void main() { expect(buttonSize.width, parentWidth - 35.0 - 20.0); }); + // Regression test for https://github.com/flutter/flutter/issues/151769 + testWidgets('expandedInsets can use EdgeInsets or EdgeInsetsDirectional', (WidgetTester tester) async { + const double parentWidth = 500.0; + final List> shortMenuItems = >[]; + for (final ShortMenu value in ShortMenu.values) { + final DropdownMenuEntry entry = DropdownMenuEntry(value: value, label: value.label); + shortMenuItems.add(entry); + } + Widget buildMenuAnchor({EdgeInsetsGeometry? expandedInsets}) { + return MaterialApp( + home: Scaffold( + body: SizedBox( + width: parentWidth, + height: parentWidth, + child: DropdownMenu( + expandedInsets: expandedInsets, + dropdownMenuEntries: shortMenuItems, + ), + ), + ), + ); + } + + // By default, the width of the text field is determined by the menu children. + await tester.pumpWidget(buildMenuAnchor()); + RenderBox box = tester.firstRenderObject(find.byType(TextField)); + expect(box.size.width, 136.0); + + await tester.tap(find.byType(TextField)); + await tester.pumpAndSettle(); + + Size buttonSize = tester.getSize(find.widgetWithText(MenuItemButton, 'I0').hitTestable()); + expect(buttonSize.width, 136.0); + + // If expandedInsets is not zero, the width of the text field should be adjusted + // based on the EdgeInsets.left and EdgeInsets.right. The top and bottom values + // will be ignored. + await tester.pumpWidget(Container()); + await tester.pumpWidget(buildMenuAnchor(expandedInsets: const EdgeInsets.only(left: 35.0, top: 50.0, right: 20.0))); + box = tester.firstRenderObject(find.byType(TextField)); + expect(box.size.width, parentWidth - 35.0 - 20.0); + Rect containerRect = tester.getRect(find.byType(SizedBox).first); + Rect dropdownMenuRect = tester.getRect(find.byType(TextField)); + expect(dropdownMenuRect.top, containerRect.top); + + await tester.tap(find.byType(TextField)); + await tester.pumpAndSettle(); + + buttonSize = tester.getSize(find.widgetWithText(MenuItemButton, 'I0')); + expect(buttonSize.width, parentWidth - 35.0 - 20.0); + + // Regression test for https://github.com/flutter/flutter/issues/151769. + // If expandedInsets is not zero, the width of the text field should be adjusted + // based on the EdgeInsets.end and EdgeInsets.start. The top and bottom values + // will be ignored. + await tester.pumpWidget(Container()); + await tester.pumpWidget(buildMenuAnchor(expandedInsets: const EdgeInsetsDirectional.only(start: 35.0, top: 50.0, end: 20.0))); + box = tester.firstRenderObject(find.byType(TextField)); + expect(box.size.width, parentWidth - 35.0 - 20.0); + containerRect = tester.getRect(find.byType(SizedBox).first); + dropdownMenuRect = tester.getRect(find.byType(TextField)); + expect(dropdownMenuRect.top, containerRect.top); + + + await tester.tap(find.byType(TextField)); + await tester.pumpAndSettle(); + buttonSize = tester.getSize(find.widgetWithText(MenuItemButton, 'I0')); + expect(buttonSize.width, parentWidth - 35.0 - 20.0); + }); + testWidgets('Material2 - The menuHeight property can be used to show a shorter scrollable menu list instead of the complete list', (WidgetTester tester) async { final ThemeData themeData = ThemeData(useMaterial3: false);