fix dropdown menu to position based on nearest navigator (#73381)
diff --git a/packages/flutter/lib/src/material/dropdown.dart b/packages/flutter/lib/src/material/dropdown.dart
index aa4fea6..ae51b4f 100644
--- a/packages/flutter/lib/src/material/dropdown.dart
+++ b/packages/flutter/lib/src/material/dropdown.dart
@@ -1188,8 +1188,6 @@
TextStyle? get _textStyle => widget.style ?? Theme.of(context).textTheme.subtitle1;
void _handleTap() {
- final RenderBox itemBox = context.findRenderObject()! as RenderBox;
- final Rect itemRect = itemBox.localToGlobal(Offset.zero) & itemBox.size;
final TextDirection? textDirection = Directionality.maybeOf(context);
final EdgeInsetsGeometry menuMargin = ButtonTheme.of(context).alignedDropdown
? _kAlignedMenuMargin
@@ -1218,6 +1216,8 @@
final NavigatorState navigator = Navigator.of(context);
assert(_dropdownRoute == null);
+ final RenderBox itemBox = context.findRenderObject()! as RenderBox;
+ final Rect itemRect = itemBox.localToGlobal(Offset.zero, ancestor: navigator.context.findRenderObject()) & itemBox.size;
_dropdownRoute = _DropdownRoute<T>(
items: menuItems,
buttonRect: menuMargin.resolve(textDirection).inflateRect(itemRect),
diff --git a/packages/flutter/test/material/dropdown_test.dart b/packages/flutter/test/material/dropdown_test.dart
index 91725d2..89fced8 100644
--- a/packages/flutter/test/material/dropdown_test.dart
+++ b/packages/flutter/test/material/dropdown_test.dart
@@ -586,6 +586,51 @@
expect(itemBoxes[1].size.width, equals(800.0 - 16.0 * 2));
});
+ testWidgets('Dropdown menu can position correctly inside a nested navigator', (WidgetTester tester) async {
+ // Regression test for https://github.com/flutter/flutter/issues/66870
+ await tester.pumpWidget(
+ MaterialApp(
+ home: Scaffold(
+ appBar: AppBar(),
+ body: Column(
+ children: <Widget>[
+ ConstrainedBox(
+ constraints: const BoxConstraints(maxWidth: 500, maxHeight: 200),
+ child: Navigator(
+ onGenerateRoute: (RouteSettings s) {
+ return MaterialPageRoute<void>(builder: (BuildContext context) {
+ return Center(
+ child: DropdownButton<int>(
+ value: 1,
+ items: const <DropdownMenuItem<int>>[
+ DropdownMenuItem<int>(
+ child: Text('First Item'),
+ value: 1,
+ ),
+ DropdownMenuItem<int>(
+ child: Text('Second Item'),
+ value: 2,
+ ),
+ ],
+ onChanged: (_) { },
+ ),
+ );
+ });
+ },
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ );
+ await tester.tap(find.text('First Item'));
+ await tester.pump();
+ final RenderBox secondItem = tester.renderObjectList<RenderBox>(find.text('Second Item')).toList()[1];
+ expect(secondItem.localToGlobal(Offset.zero).dx, equals(150.0));
+ expect(secondItem.localToGlobal(Offset.zero).dy, equals(176.0));
+ });
+
testWidgets('Dropdown screen edges', (WidgetTester tester) async {
int? value = 4;
final List<DropdownMenuItem<int>> items = <DropdownMenuItem<int>>[