diff --git a/packages/flutter/lib/src/material/popup_menu.dart b/packages/flutter/lib/src/material/popup_menu.dart index c86d124bdc..a80e12d468 100644 --- a/packages/flutter/lib/src/material/popup_menu.dart +++ b/packages/flutter/lib/src/material/popup_menu.dart @@ -756,12 +756,7 @@ class _PopupMenuRoute extends PopupRoute { menu = Theme(data: theme!, child: menu); } - return MediaQuery.removePadding( - context: context, - removeTop: true, - removeBottom: true, - removeLeft: true, - removeRight: true, + return SafeArea( child: Builder( builder: (BuildContext context) { return CustomSingleChildLayout( diff --git a/packages/flutter/test/material/popup_menu_test.dart b/packages/flutter/test/material/popup_menu_test.dart index 292ebd4c91..85da8f5819 100644 --- a/packages/flutter/test/material/popup_menu_test.dart +++ b/packages/flutter/test/material/popup_menu_test.dart @@ -1583,6 +1583,119 @@ void main() { expect(RendererBinding.instance!.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); + + testWidgets('PopupMenu in AppBar does not overlap with the status bar', (WidgetTester tester) async { + const List> choices = >[ + PopupMenuItem(value: 1, child: Text('Item 1')), + PopupMenuItem(value: 2, child: Text('Item 2')), + PopupMenuItem(value: 3, child: Text('Item 3')), + ]; + + const double statusBarHeight = 24.0; + final PopupMenuItem firstItem = choices[0]; + int _selectedValue = choices[0].value; + + await tester.pumpWidget( + MaterialApp( + builder: (BuildContext context, Widget child) { + return MediaQuery( + data: const MediaQueryData(padding: EdgeInsets.only(top: statusBarHeight)), // status bar + child: child, + ); + }, + home: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return Scaffold( + appBar: AppBar( + title: const Text('PopupMenu Test'), + actions: [ + PopupMenuButton( + onSelected: (int result) { + setState(() { + _selectedValue = result; + }); + }, + initialValue: _selectedValue, + itemBuilder: (BuildContext context) { + return choices; + }, + ), + ], + ), + ); + }, + ), + ), + ); + + await tester.tap(find.byIcon(Icons.more_vert)); + await tester.pumpAndSettle(); + + // Tap third item. + await tester.tap(find.text('Item 3')); + await tester.pumpAndSettle(); + + // Open popupMenu again. + await tester.tap(find.byIcon(Icons.more_vert)); + await tester.pumpAndSettle(); + + // Check whether the first item is not overlapping with status bar. + expect(tester.getTopLeft(find.byWidget(firstItem)).dy, greaterThan(statusBarHeight)); + }); + + testWidgets('Vertically long PopupMenu does not overlap with the status bar and bottom notch', (WidgetTester tester) async { + const double windowPaddingTop = 44; + const double windowPaddingBottom = 34; + final GlobalKey _firstKey = GlobalKey(); + final GlobalKey _lastKey = GlobalKey(); + + await tester.pumpWidget( + MaterialApp( + builder: (BuildContext context, Widget child) { + return MediaQuery( + data: const MediaQueryData( + padding: EdgeInsets.only( + top: windowPaddingTop, + bottom: windowPaddingBottom, + ), + ), + child: child, + ); + }, + home: Scaffold( + appBar: AppBar( + title: const Text('PopupMenu Test'), + ), + body: PopupMenuButton( + child: const Text('Show Menu'), + itemBuilder: (BuildContext context) => Iterable>.generate( + 20, (int i) => PopupMenuItem( + // Set globalKey to the first and last item. + key: i == 0 ? _firstKey : i == 19 ? _lastKey : null, + value: i, + child: Text('Item $i'), + ), + ).toList(), + ), + ), + ), + ); + + await tester.tap(find.text('Show Menu')); + await tester.pumpAndSettle(); + + // Check whether the first item is not overlapping with status bar. + expect(tester.getTopLeft(find.byKey(_firstKey)).dy, greaterThan(windowPaddingTop)); + + await tester.ensureVisible(find.byKey(_lastKey, skipOffstage: false)); + await tester.pumpAndSettle(); + + // Check whether the last item is not overlapping with bottom notch. + expect( + tester.getBottomLeft(find.byKey(_lastKey)).dy, + lessThan(600 - windowPaddingBottom), // Device height is 600. + ); + }); } class TestApp extends StatefulWidget {