@@ -1583,6 +1583,119 @@ void main() {
15831583
15841584 expect (RendererBinding .instance! .mouseTracker.debugDeviceActiveCursor (1 ), SystemMouseCursors .basic);
15851585 });
1586+
1587+ testWidgets ('PopupMenu in AppBar does not overlap with the status bar' , (WidgetTester tester) async {
1588+ const List <PopupMenuItem <int >> choices = < PopupMenuItem <int >> [
1589+ PopupMenuItem <int >(value: 1 , child: Text ('Item 1' )),
1590+ PopupMenuItem <int >(value: 2 , child: Text ('Item 2' )),
1591+ PopupMenuItem <int >(value: 3 , child: Text ('Item 3' )),
1592+ ];
1593+
1594+ const double statusBarHeight = 24.0 ;
1595+ final PopupMenuItem <int > firstItem = choices[0 ];
1596+ int _selectedValue = choices[0 ].value;
1597+
1598+ await tester.pumpWidget (
1599+ MaterialApp (
1600+ builder: (BuildContext context, Widget child) {
1601+ return MediaQuery (
1602+ data: const MediaQueryData (padding: EdgeInsets .only (top: statusBarHeight)), // status bar
1603+ child: child,
1604+ );
1605+ },
1606+ home: StatefulBuilder (
1607+ builder: (BuildContext context, StateSetter setState) {
1608+ return Scaffold (
1609+ appBar: AppBar (
1610+ title: const Text ('PopupMenu Test' ),
1611+ actions: < Widget > [
1612+ PopupMenuButton <int >(
1613+ onSelected: (int result) {
1614+ setState (() {
1615+ _selectedValue = result;
1616+ });
1617+ },
1618+ initialValue: _selectedValue,
1619+ itemBuilder: (BuildContext context) {
1620+ return choices;
1621+ },
1622+ ),
1623+ ],
1624+ ),
1625+ );
1626+ },
1627+ ),
1628+ ),
1629+ );
1630+
1631+ await tester.tap (find.byIcon (Icons .more_vert));
1632+ await tester.pumpAndSettle ();
1633+
1634+ // Tap third item.
1635+ await tester.tap (find.text ('Item 3' ));
1636+ await tester.pumpAndSettle ();
1637+
1638+ // Open popupMenu again.
1639+ await tester.tap (find.byIcon (Icons .more_vert));
1640+ await tester.pumpAndSettle ();
1641+
1642+ // Check whether the first item is not overlapping with status bar.
1643+ expect (tester.getTopLeft (find.byWidget (firstItem)).dy, greaterThan (statusBarHeight));
1644+ });
1645+
1646+ testWidgets ('Vertically long PopupMenu does not overlap with the status bar and bottom notch' , (WidgetTester tester) async {
1647+ const double windowPaddingTop = 44 ;
1648+ const double windowPaddingBottom = 34 ;
1649+ final GlobalKey _firstKey = GlobalKey ();
1650+ final GlobalKey _lastKey = GlobalKey ();
1651+
1652+ await tester.pumpWidget (
1653+ MaterialApp (
1654+ builder: (BuildContext context, Widget child) {
1655+ return MediaQuery (
1656+ data: const MediaQueryData (
1657+ padding: EdgeInsets .only (
1658+ top: windowPaddingTop,
1659+ bottom: windowPaddingBottom,
1660+ ),
1661+ ),
1662+ child: child,
1663+ );
1664+ },
1665+ home: Scaffold (
1666+ appBar: AppBar (
1667+ title: const Text ('PopupMenu Test' ),
1668+ ),
1669+ body: PopupMenuButton <int >(
1670+ child: const Text ('Show Menu' ),
1671+ itemBuilder: (BuildContext context) => Iterable <PopupMenuItem <int >>.generate (
1672+ 20 , (int i) => PopupMenuItem <int >(
1673+ // Set globalKey to the first and last item.
1674+ key: i == 0 ? _firstKey : i == 19 ? _lastKey : null ,
1675+ value: i,
1676+ child: Text ('Item $i ' ),
1677+ ),
1678+ ).toList (),
1679+ ),
1680+ ),
1681+ ),
1682+ );
1683+
1684+ await tester.tap (find.text ('Show Menu' ));
1685+ await tester.pumpAndSettle ();
1686+
1687+ // Check whether the first item is not overlapping with status bar.
1688+ expect (tester.getTopLeft (find.byKey (_firstKey)).dy, greaterThan (windowPaddingTop));
1689+
1690+ await tester.ensureVisible (find.byKey (_lastKey, skipOffstage: false ));
1691+ await tester.pumpAndSettle ();
1692+
1693+ // Check whether the last item is not overlapping with bottom notch.
1694+ expect (
1695+ tester.getBottomLeft (find.byKey (_lastKey)).dy,
1696+ lessThan (600 - windowPaddingBottom), // Device height is 600.
1697+ );
1698+ });
15861699}
15871700
15881701class TestApp extends StatefulWidget {
0 commit comments