Add vertical alignment offset to the ``MenuAnchor`` widget when overflowing (#123740)
Positioning of cascading menus.
This commit is contained in:
@@ -3177,7 +3177,12 @@ class _MenuLayout extends SingleChildLayoutDelegate {
|
||||
} else if (offBottom(y)) {
|
||||
final double newY = anchorRect.top - childSize.height;
|
||||
if (!offTop(newY)) {
|
||||
y = newY;
|
||||
// Only move the menu up if its parent is horizontal (MenuAchor/MenuBar).
|
||||
if (parentOrientation == Axis.horizontal) {
|
||||
y = newY - alignmentOffset.dy;
|
||||
} else {
|
||||
y = newY;
|
||||
}
|
||||
} else {
|
||||
y = allowedRect.bottom - childSize.height;
|
||||
}
|
||||
|
||||
@@ -2481,6 +2481,105 @@ void main() {
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('vertically constrained menus are positioned above the anchor by default', (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.bottomLeft,
|
||||
child: MenuAnchor(
|
||||
menuChildren: const <Widget> [
|
||||
MenuItemButton(child: Text('Button1'),
|
||||
),
|
||||
],
|
||||
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();
|
||||
|
||||
expect(find.byType(MenuItemButton), findsNWidgets(1));
|
||||
// Test the default offset (0, 0) vertical position.
|
||||
expect(
|
||||
collectSubmenuRects(),
|
||||
equals(const <Rect>[
|
||||
Rect.fromLTRB(0.0, 488.0, 122.0, 552.0),
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('vertically constrained menus are positioned above the anchor with the provided offset', (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.bottomLeft,
|
||||
child: MenuAnchor(
|
||||
alignmentOffset: const Offset(0, 50),
|
||||
menuChildren: const <Widget> [
|
||||
MenuItemButton(child: Text('Button1'),
|
||||
),
|
||||
],
|
||||
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();
|
||||
|
||||
expect(find.byType(MenuItemButton), findsNWidgets(1));
|
||||
// Test the offset (0, 50) vertical position.
|
||||
expect(
|
||||
collectSubmenuRects(),
|
||||
equals(const <Rect>[
|
||||
Rect.fromLTRB(0.0, 438.0, 122.0, 502.0),
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
Future<void> buildDensityPaddingApp(WidgetTester tester, {
|
||||
required TextDirection textDirection,
|
||||
VisualDensity visualDensity = VisualDensity.standard,
|
||||
|
||||
Reference in New Issue
Block a user