From d173c660d8e23e86bbbfae6d4a2f8d26d1fd84b5 Mon Sep 17 00:00:00 2001 From: Henry Riehl <73116038+whiskeyPeak@users.noreply.github.com> Date: Tue, 28 Mar 2023 21:59:52 +0100 Subject: [PATCH] Add alignmentOffset when menu is positioned on the opposite side (#122812) Add alignmentOffset when menu is positioned on the opposite side --- .../flutter/lib/src/material/menu_anchor.dart | 4 +- .../test/material/menu_anchor_test.dart | 154 ++++++++++++++++++ 2 files changed, 156 insertions(+), 2 deletions(-) diff --git a/packages/flutter/lib/src/material/menu_anchor.dart b/packages/flutter/lib/src/material/menu_anchor.dart index 1042b20058e..77838b8f26f 100644 --- a/packages/flutter/lib/src/material/menu_anchor.dart +++ b/packages/flutter/lib/src/material/menu_anchor.dart @@ -3122,7 +3122,7 @@ class _MenuLayout extends SingleChildLayoutDelegate { if (parentOrientation != orientation) { x = allowedRect.left; } else { - final double newX = anchorRect.right; + final double newX = anchorRect.right + alignmentOffset.dx; if (!offRightSide(newX)) { x = newX; } else { @@ -3133,7 +3133,7 @@ class _MenuLayout extends SingleChildLayoutDelegate { if (parentOrientation != orientation) { x = allowedRect.right - childSize.width; } else { - final double newX = anchorRect.left - childSize.width; + final double newX = anchorRect.left - childSize.width - alignmentOffset.dx; if (!offLeftSide(newX)) { x = newX; } else { diff --git a/packages/flutter/test/material/menu_anchor_test.dart b/packages/flutter/test/material/menu_anchor_test.dart index 2ba4afadabb..655eaded904 100644 --- a/packages/flutter/test/material/menu_anchor_test.dart +++ b/packages/flutter/test/material/menu_anchor_test.dart @@ -2266,6 +2266,160 @@ void main() { ); }); + testWidgets('constrained menus show up in the right place with offset in LTR', (WidgetTester tester) async { + await changeSurfaceSize(tester, const Size(800, 600)); + await tester.pumpWidget( + MaterialApp( + home: Builder( + builder: (BuildContext context) { + return Directionality( + textDirection: TextDirection.ltr, + child: Align( + alignment: Alignment.topLeft, + child: MenuAnchor( + menuChildren: const [ + SubmenuButton( + alignmentOffset: Offset(10, 0), + menuChildren: [ + SubmenuButton( + menuChildren: [ + SubmenuButton( + alignmentOffset: Offset(10, 0), + menuChildren: [ + SubmenuButton( + menuChildren: [ + ], + child: Text('SubMenuButton4'), + ), + ], + child: Text('SubMenuButton3'), + ), + ], + child: Text('SubMenuButton2'), + ), + ], + child: Text('SubMenuButton1'), + ), + ], + builder: (BuildContext context, MenuController controller, Widget? child) { + return FilledButton( + onPressed: () { + if (controller.isOpen) { + controller.close(); + } else { + controller.open(); + } + }, + child: const Text('Tap me'), + ); + }, + ), + ), + ); + }, + ), + ), + ); + await tester.pump(); + + await tester.tap(find.text('Tap me')); + await tester.pump(); + await tester.tap(find.text('SubMenuButton1')); + await tester.pump(); + await tester.tap(find.text('SubMenuButton2')); + await tester.pump(); + await tester.tap(find.text('SubMenuButton3')); + await tester.pump(); + + expect(find.byType(SubmenuButton), findsNWidgets(4)); + expect( + collectSubmenuRects(), + equals(const [ + Rect.fromLTRB(0.0, 48.0, 256.0, 112.0), + Rect.fromLTRB(266.0, 48.0, 522.0, 112.0), + Rect.fromLTRB(522.0, 48.0, 778.0, 112.0), + Rect.fromLTRB(256.0, 48.0, 512.0, 112.0), + ]), + ); + }); + + testWidgets('constrained menus show up in the right place with offset in RTL', (WidgetTester tester) async { + await changeSurfaceSize(tester, const Size(800, 600)); + await tester.pumpWidget( + MaterialApp( + home: Builder( + builder: (BuildContext context) { + return Directionality( + textDirection: TextDirection.rtl, + child: Align( + alignment: Alignment.topRight, + child: MenuAnchor( + menuChildren: const [ + SubmenuButton( + alignmentOffset: Offset(10, 0), + menuChildren: [ + SubmenuButton( + menuChildren: [ + SubmenuButton( + alignmentOffset: Offset(10, 0), + menuChildren: [ + SubmenuButton( + menuChildren: [ + ], + child: Text('SubMenuButton4'), + ), + ], + child: Text('SubMenuButton3'), + ), + ], + child: Text('SubMenuButton2'), + ), + ], + child: Text('SubMenuButton1'), + ), + ], + builder: (BuildContext context, MenuController controller, Widget? child) { + return FilledButton( + onPressed: () { + if (controller.isOpen) { + controller.close(); + } else { + controller.open(); + } + }, + child: const Text('Tap me'), + ); + }, + ), + ), + ); + }, + ), + ), + ); + await tester.pump(); + + await tester.tap(find.text('Tap me')); + await tester.pump(); + await tester.tap(find.text('SubMenuButton1')); + await tester.pump(); + await tester.tap(find.text('SubMenuButton2')); + await tester.pump(); + await tester.tap(find.text('SubMenuButton3')); + await tester.pump(); + + expect(find.byType(SubmenuButton), findsNWidgets(4)); + expect( + collectSubmenuRects(), + equals(const [ + Rect.fromLTRB(544.0, 48.0, 800.0, 112.0), + Rect.fromLTRB(278.0, 48.0, 534.0, 112.0), + Rect.fromLTRB(22.0, 48.0, 278.0, 112.0), + Rect.fromLTRB(288.0, 48.0, 544.0, 112.0), + ]), + ); + }); + Future buildDensityPaddingApp(WidgetTester tester, { required TextDirection textDirection, VisualDensity visualDensity = VisualDensity.standard,