Skip to content

Commit d173c66

Browse files
authored
Add alignmentOffset when menu is positioned on the opposite side (#122812)
Add alignmentOffset when menu is positioned on the opposite side
1 parent ed713ad commit d173c66

File tree

2 files changed

+156
-2
lines changed

2 files changed

+156
-2
lines changed

packages/flutter/lib/src/material/menu_anchor.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3122,7 +3122,7 @@ class _MenuLayout extends SingleChildLayoutDelegate {
31223122
if (parentOrientation != orientation) {
31233123
x = allowedRect.left;
31243124
} else {
3125-
final double newX = anchorRect.right;
3125+
final double newX = anchorRect.right + alignmentOffset.dx;
31263126
if (!offRightSide(newX)) {
31273127
x = newX;
31283128
} else {
@@ -3133,7 +3133,7 @@ class _MenuLayout extends SingleChildLayoutDelegate {
31333133
if (parentOrientation != orientation) {
31343134
x = allowedRect.right - childSize.width;
31353135
} else {
3136-
final double newX = anchorRect.left - childSize.width;
3136+
final double newX = anchorRect.left - childSize.width - alignmentOffset.dx;
31373137
if (!offLeftSide(newX)) {
31383138
x = newX;
31393139
} else {

packages/flutter/test/material/menu_anchor_test.dart

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2266,6 +2266,160 @@ void main() {
22662266
);
22672267
});
22682268

2269+
testWidgets('constrained menus show up in the right place with offset in LTR', (WidgetTester tester) async {
2270+
await changeSurfaceSize(tester, const Size(800, 600));
2271+
await tester.pumpWidget(
2272+
MaterialApp(
2273+
home: Builder(
2274+
builder: (BuildContext context) {
2275+
return Directionality(
2276+
textDirection: TextDirection.ltr,
2277+
child: Align(
2278+
alignment: Alignment.topLeft,
2279+
child: MenuAnchor(
2280+
menuChildren: const <Widget> [
2281+
SubmenuButton(
2282+
alignmentOffset: Offset(10, 0),
2283+
menuChildren: <Widget> [
2284+
SubmenuButton(
2285+
menuChildren: <Widget> [
2286+
SubmenuButton(
2287+
alignmentOffset: Offset(10, 0),
2288+
menuChildren: <Widget> [
2289+
SubmenuButton(
2290+
menuChildren: <Widget> [
2291+
],
2292+
child: Text('SubMenuButton4'),
2293+
),
2294+
],
2295+
child: Text('SubMenuButton3'),
2296+
),
2297+
],
2298+
child: Text('SubMenuButton2'),
2299+
),
2300+
],
2301+
child: Text('SubMenuButton1'),
2302+
),
2303+
],
2304+
builder: (BuildContext context, MenuController controller, Widget? child) {
2305+
return FilledButton(
2306+
onPressed: () {
2307+
if (controller.isOpen) {
2308+
controller.close();
2309+
} else {
2310+
controller.open();
2311+
}
2312+
},
2313+
child: const Text('Tap me'),
2314+
);
2315+
},
2316+
),
2317+
),
2318+
);
2319+
},
2320+
),
2321+
),
2322+
);
2323+
await tester.pump();
2324+
2325+
await tester.tap(find.text('Tap me'));
2326+
await tester.pump();
2327+
await tester.tap(find.text('SubMenuButton1'));
2328+
await tester.pump();
2329+
await tester.tap(find.text('SubMenuButton2'));
2330+
await tester.pump();
2331+
await tester.tap(find.text('SubMenuButton3'));
2332+
await tester.pump();
2333+
2334+
expect(find.byType(SubmenuButton), findsNWidgets(4));
2335+
expect(
2336+
collectSubmenuRects(),
2337+
equals(const <Rect>[
2338+
Rect.fromLTRB(0.0, 48.0, 256.0, 112.0),
2339+
Rect.fromLTRB(266.0, 48.0, 522.0, 112.0),
2340+
Rect.fromLTRB(522.0, 48.0, 778.0, 112.0),
2341+
Rect.fromLTRB(256.0, 48.0, 512.0, 112.0),
2342+
]),
2343+
);
2344+
});
2345+
2346+
testWidgets('constrained menus show up in the right place with offset in RTL', (WidgetTester tester) async {
2347+
await changeSurfaceSize(tester, const Size(800, 600));
2348+
await tester.pumpWidget(
2349+
MaterialApp(
2350+
home: Builder(
2351+
builder: (BuildContext context) {
2352+
return Directionality(
2353+
textDirection: TextDirection.rtl,
2354+
child: Align(
2355+
alignment: Alignment.topRight,
2356+
child: MenuAnchor(
2357+
menuChildren: const <Widget> [
2358+
SubmenuButton(
2359+
alignmentOffset: Offset(10, 0),
2360+
menuChildren: <Widget> [
2361+
SubmenuButton(
2362+
menuChildren: <Widget> [
2363+
SubmenuButton(
2364+
alignmentOffset: Offset(10, 0),
2365+
menuChildren: <Widget> [
2366+
SubmenuButton(
2367+
menuChildren: <Widget> [
2368+
],
2369+
child: Text('SubMenuButton4'),
2370+
),
2371+
],
2372+
child: Text('SubMenuButton3'),
2373+
),
2374+
],
2375+
child: Text('SubMenuButton2'),
2376+
),
2377+
],
2378+
child: Text('SubMenuButton1'),
2379+
),
2380+
],
2381+
builder: (BuildContext context, MenuController controller, Widget? child) {
2382+
return FilledButton(
2383+
onPressed: () {
2384+
if (controller.isOpen) {
2385+
controller.close();
2386+
} else {
2387+
controller.open();
2388+
}
2389+
},
2390+
child: const Text('Tap me'),
2391+
);
2392+
},
2393+
),
2394+
),
2395+
);
2396+
},
2397+
),
2398+
),
2399+
);
2400+
await tester.pump();
2401+
2402+
await tester.tap(find.text('Tap me'));
2403+
await tester.pump();
2404+
await tester.tap(find.text('SubMenuButton1'));
2405+
await tester.pump();
2406+
await tester.tap(find.text('SubMenuButton2'));
2407+
await tester.pump();
2408+
await tester.tap(find.text('SubMenuButton3'));
2409+
await tester.pump();
2410+
2411+
expect(find.byType(SubmenuButton), findsNWidgets(4));
2412+
expect(
2413+
collectSubmenuRects(),
2414+
equals(const <Rect>[
2415+
Rect.fromLTRB(544.0, 48.0, 800.0, 112.0),
2416+
Rect.fromLTRB(278.0, 48.0, 534.0, 112.0),
2417+
Rect.fromLTRB(22.0, 48.0, 278.0, 112.0),
2418+
Rect.fromLTRB(288.0, 48.0, 544.0, 112.0),
2419+
]),
2420+
);
2421+
});
2422+
22692423
Future<void> buildDensityPaddingApp(WidgetTester tester, {
22702424
required TextDirection textDirection,
22712425
VisualDensity visualDensity = VisualDensity.standard,

0 commit comments

Comments
 (0)