From 4aafcce483ffbcb0c85767bcaefae005784ab2e2 Mon Sep 17 00:00:00 2001 From: PurplePolyhedron <120297255+PurplePolyhedron@users.noreply.github.com> Date: Thu, 13 Feb 2025 16:34:37 +1000 Subject: [PATCH] fix `DropdownMenu` crashes when provided menuStyle with small maximumSize (#162380) fix #162356 Previously `DropdownMenu` overwrites `minimumSize` in `menuStyle` to be the width of the `TextField` Now it set the `minimumSize` to be the min between the width of the `TextField` and the width of `maximumSize`, so that the menu can be smaller than the `TextField`. ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md --- .../lib/src/material/dropdown_menu.dart | 12 ++++- .../test/material/dropdown_menu_test.dart | 46 +++++++++++++++++++ 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/packages/flutter/lib/src/material/dropdown_menu.dart b/packages/flutter/lib/src/material/dropdown_menu.dart index aad2210faa0..1de959f1a5f 100644 --- a/packages/flutter/lib/src/material/dropdown_menu.dart +++ b/packages/flutter/lib/src/material/dropdown_menu.dart @@ -967,11 +967,19 @@ class _DropdownMenuState extends State> { final double? anchorWidth = getWidth(_anchorKey); if (widget.width != null) { effectiveMenuStyle = effectiveMenuStyle.copyWith( - minimumSize: MaterialStatePropertyAll(Size(widget.width!, 0.0)), + minimumSize: MaterialStateProperty.resolveWith((Set states) { + final double? effectiveMaximumWidth = + effectiveMenuStyle!.maximumSize?.resolve(states)?.width; + return Size(math.min(widget.width!, effectiveMaximumWidth ?? 0.0), 0.0); + }), ); } else if (anchorWidth != null) { effectiveMenuStyle = effectiveMenuStyle.copyWith( - minimumSize: MaterialStatePropertyAll(Size(anchorWidth, 0.0)), + minimumSize: MaterialStateProperty.resolveWith((Set states) { + final double? effectiveMaximumWidth = + effectiveMenuStyle!.maximumSize?.resolve(states)?.width; + return Size(math.min(anchorWidth, effectiveMaximumWidth ?? 0.0), 0.0); + }), ); } diff --git a/packages/flutter/test/material/dropdown_menu_test.dart b/packages/flutter/test/material/dropdown_menu_test.dart index 39e06805c82..529557a7ab8 100644 --- a/packages/flutter/test/material/dropdown_menu_test.dart +++ b/packages/flutter/test/material/dropdown_menu_test.dart @@ -3952,6 +3952,52 @@ void main() { textField = tester.widget(find.byType(TextField)); expect(textField.textInputAction, TextInputAction.next); }); + + testWidgets('items can be constrainted to be smaller than the text field with menuStyle', ( + WidgetTester tester, + ) async { + const String longLabel = 'This is a long text that it can overflow.'; + await tester.pumpWidget( + const MaterialApp( + home: Scaffold( + body: DropdownMenu( + dropdownMenuEntries: >[ + DropdownMenuEntry(value: 0, label: longLabel), + ], + menuStyle: MenuStyle(maximumSize: WidgetStatePropertyAll(Size(150.0, 50.0))), + ), + ), + ), + ); + + await tester.tap(find.byType(TextField)); + await tester.pumpAndSettle(); + + expect(tester.takeException(), isNull); + expect(tester.getSize(findMenuItemButton(longLabel)).width, 150.0); + + // The overwrite of menuStyle is different when a width is provided, + // So it needs to be tested separately. + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: DropdownMenu( + width: 200.0, + dropdownMenuEntries: menuChildren, + menuStyle: const MenuStyle( + maximumSize: WidgetStatePropertyAll(Size(150.0, 50.0)), + ), + ), + ), + ), + ); + + await tester.tap(find.byType(TextField)); + await tester.pumpAndSettle(); + + expect(tester.takeException(), isNull); + expect(tester.getSize(findMenuItemButton(menuChildren.first.label)).width, 150.0); + }); } enum TestMenu {