From 00cd3edae385f95fee9b6159c8c42886a4117d40 Mon Sep 17 00:00:00 2001 From: Valentin Vignal <32538273+ValentinVignal@users.noreply.github.com> Date: Wed, 3 May 2023 01:02:55 +0800 Subject: [PATCH] Align the Popup Menu under its child (#125534) Align the `PopupMenu` under its child. Before: ![image](https://user-images.githubusercontent.com/32538273/234468262-beddb257-5f5a-422f-a678-c26efc52dc07.png) After: ![image](https://user-images.githubusercontent.com/32538273/234468233-3ea4d741-b04c-4012-bdd7-a36ecedc029c.png) *List which issues are fixed by this PR. You must list at least one issue.* Fixes https://github.com/flutter/flutter/issues/125474 *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* --- .../flutter/lib/src/material/popup_menu.dart | 8 +++- .../test/material/popup_menu_test.dart | 38 +++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/packages/flutter/lib/src/material/popup_menu.dart b/packages/flutter/lib/src/material/popup_menu.dart index 4f7c95d1af..c830a82875 100644 --- a/packages/flutter/lib/src/material/popup_menu.dart +++ b/packages/flutter/lib/src/material/popup_menu.dart @@ -1241,12 +1241,16 @@ class PopupMenuButtonState extends State> { final RenderBox button = context.findRenderObject()! as RenderBox; final RenderBox overlay = Navigator.of(context).overlay!.context.findRenderObject()! as RenderBox; final PopupMenuPosition popupMenuPosition = widget.position ?? popupMenuTheme.position ?? PopupMenuPosition.over; - final Offset offset; + late Offset offset; switch (popupMenuPosition) { case PopupMenuPosition.over: offset = widget.offset; case PopupMenuPosition.under: - offset = Offset(0.0, button.size.height - (widget.padding.vertical / 2)) + widget.offset; + offset = Offset(0.0, button.size.height) + widget.offset; + if (widget.child == null) { + // Remove the padding of the icon button. + offset -= Offset(0.0, widget.padding.vertical / 2); + } } final RelativeRect position = RelativeRect.fromRect( Rect.fromPoints( diff --git a/packages/flutter/test/material/popup_menu_test.dart b/packages/flutter/test/material/popup_menu_test.dart index 0772a953d7..a037285242 100644 --- a/packages/flutter/test/material/popup_menu_test.dart +++ b/packages/flutter/test/material/popup_menu_test.dart @@ -3222,6 +3222,44 @@ void main() { await tester.pumpAndSettle(); expect(currentRouteSetting.name, '/'); }); + + testWidgets('Popup menu is positioned under the child', (WidgetTester tester) async { + final Key popupButtonKey = UniqueKey(); + final Key childKey = UniqueKey(); + await tester.pumpWidget( + MaterialApp( + home: Material( + child: Column( + children: [ + PopupMenuButton( + key: popupButtonKey, + position: PopupMenuPosition.under, + itemBuilder: (BuildContext context) { + return >[ + const PopupMenuItem( + child: Text('Example'), + ), + ]; + }, + child: SizedBox( + key: childKey, + height: 50, + width: 50, + ) + ), + ], + ), + ), + ) + ); + + await tester.tap(find.byKey(popupButtonKey)); + await tester.pumpAndSettle(); + + final Offset childBottomLeft = tester.getBottomLeft(find.byKey(childKey)); + final Offset menuTopLeft = tester.getTopLeft(find.bySemanticsLabel('Popup menu')); + expect(childBottomLeft, menuTopLeft); + }); } class TestApp extends StatelessWidget {