From 7aa17231ac291036d42e4d042be47f94f5afb56c Mon Sep 17 00:00:00 2001 From: Kate Lovett Date: Thu, 4 Feb 2021 12:01:04 -0600 Subject: [PATCH] Revert "Reland "Update PopupMenuButton to match Material Design spec"" (#75338) --- .../test_driver/main_test.dart | 37 ++-- .../flutter/lib/src/material/popup_menu.dart | 150 ++++----------- .../test/material/popup_menu_test.dart | 177 +++--------------- .../flutter_localizations/test/text_test.dart | 34 ++-- 4 files changed, 92 insertions(+), 306 deletions(-) diff --git a/dev/integration_tests/android_semantics_testing/test_driver/main_test.dart b/dev/integration_tests/android_semantics_testing/test_driver/main_test.dart index 621cf7c4eb..20608bbfa1 100644 --- a/dev/integration_tests/android_semantics_testing/test_driver/main_test.dart +++ b/dev/integration_tests/android_semantics_testing/test_driver/main_test.dart @@ -409,14 +409,8 @@ void main() { }); test('Popup Menu has correct Android semantics', () async { - final SerializableFinder button = find.descendant( - of: find.byValueKey(popupButtonKeyValue), - matching: find.byType('Semantics'), - firstMatchOnly: true, - ); - expect( - await getSemantics(button), + await getSemantics(find.byValueKey(popupButtonKeyValue)), hasAndroidSemantics( className: AndroidClassName.button, isChecked: false, @@ -438,21 +432,20 @@ void main() { for (final String item in popupItems) { expect( - await getSemantics(find.byValueKey('$popupKeyValue.$item')), - hasAndroidSemantics( - className: AndroidClassName.button, - isChecked: false, - isCheckable: false, - isEnabled: true, - isFocusable: true, - actions: [ - if (item == popupItems.first) AndroidSemanticsAction.clearAccessibilityFocus, - if (item != popupItems.first) AndroidSemanticsAction.accessibilityFocus, - AndroidSemanticsAction.click, - ], - ), - reason: "Popup $item doesn't have the right semantics", - ); + await getSemantics(find.byValueKey('$popupKeyValue.$item')), + hasAndroidSemantics( + className: AndroidClassName.button, + isChecked: false, + isCheckable: false, + isEnabled: true, + isFocusable: true, + actions: [ + if (item == popupItems.first) AndroidSemanticsAction.clearAccessibilityFocus, + if (item != popupItems.first) AndroidSemanticsAction.accessibilityFocus, + AndroidSemanticsAction.click, + ], + ), + reason: "Popup $item doesn't have the right semantics"); } await driver.tap(find.byValueKey('$popupKeyValue.${popupItems.first}')); diff --git a/packages/flutter/lib/src/material/popup_menu.dart b/packages/flutter/lib/src/material/popup_menu.dart index 498ce83aec..1d3ea6b101 100644 --- a/packages/flutter/lib/src/material/popup_menu.dart +++ b/packages/flutter/lib/src/material/popup_menu.dart @@ -599,15 +599,7 @@ class _PopupMenu extends StatelessWidget { // Positioning of the menu on the screen. class _PopupMenuRouteLayout extends SingleChildLayoutDelegate { - _PopupMenuRouteLayout( - this.position, - this.itemSizes, - this.selectedItemIndex, - this.textDirection, - this.topPadding, - this.bottomPadding, - this.placement, - ); + _PopupMenuRouteLayout(this.position, this.itemSizes, this.selectedItemIndex, this.textDirection); // Rectangle of underlying button, relative to the overlay's dimensions. final RelativeRect position; @@ -623,15 +615,6 @@ class _PopupMenuRouteLayout extends SingleChildLayoutDelegate { // Whether to prefer going to the left or to the right. final TextDirection textDirection; - // Top padding of unsafe area. - final double topPadding; - - // Bottom padding of unsafe area. - final double bottomPadding; - - // The placement of the menu. - final PopupMenuPlacement placement; - // We put the child wherever position specifies, so long as it will fit within // the specified parent size padded (inset) by 8. If necessary, we adjust the // child's position so that it fits. @@ -641,8 +624,7 @@ class _PopupMenuRouteLayout extends SingleChildLayoutDelegate { // The menu can be at most the size of the overlay minus 8.0 pixels in each // direction. return BoxConstraints.loose( - constraints.biggest - Offset(_kMenuScreenPadding * 2.0, - _kMenuScreenPadding * 2.0 + topPadding + bottomPadding) as Size, + constraints.biggest - const Offset(_kMenuScreenPadding * 2.0, _kMenuScreenPadding * 2.0) as Size, ); } @@ -652,23 +634,14 @@ class _PopupMenuRouteLayout extends SingleChildLayoutDelegate { // childSize: The size of the menu, when fully open, as determined by // getConstraintsForChild. - final double buttonHeight = size.height - position.top - position.bottom; - // Find the ideal vertical position. - // Default vertical position is below the element that generates it. - double y = placement == PopupMenuPlacement.belowButton - ? position.top + buttonHeight - : position.top; + double y = position.top; if (selectedItemIndex != null && itemSizes != null) { double selectedItemOffset = _kMenuVerticalPadding; for (int index = 0; index < selectedItemIndex!; index += 1) selectedItemOffset += itemSizes[index]!.height; selectedItemOffset += itemSizes[selectedItemIndex!]!.height / 2; - if (placement == PopupMenuPlacement.belowButton) { - y = y - buttonHeight / 2.0 - selectedItemOffset; - } else { - y = y + buttonHeight / 2.0 - selectedItemOffset; - } + y = position.top + (size.height - position.top - position.bottom) / 2.0 - selectedItemOffset; } // Find the ideal horizontal position. @@ -698,10 +671,10 @@ class _PopupMenuRouteLayout extends SingleChildLayoutDelegate { x = _kMenuScreenPadding; else if (x + childSize.width > size.width - _kMenuScreenPadding) x = size.width - childSize.width - _kMenuScreenPadding; - if (y < _kMenuScreenPadding + topPadding) - y = _kMenuScreenPadding + topPadding; + if (y < _kMenuScreenPadding) + y = _kMenuScreenPadding; else if (y + childSize.height > size.height - _kMenuScreenPadding) - y = size.height - bottomPadding - _kMenuScreenPadding - childSize.height ; + y = size.height - childSize.height - _kMenuScreenPadding; return Offset(x, y); } @@ -713,9 +686,9 @@ class _PopupMenuRouteLayout extends SingleChildLayoutDelegate { assert(itemSizes.length == oldDelegate.itemSizes.length); return position != oldDelegate.position - || selectedItemIndex != oldDelegate.selectedItemIndex - || textDirection != oldDelegate.textDirection - || !listEquals(itemSizes, oldDelegate.itemSizes); + || selectedItemIndex != oldDelegate.selectedItemIndex + || textDirection != oldDelegate.textDirection + || !listEquals(itemSizes, oldDelegate.itemSizes); } } @@ -730,7 +703,6 @@ class _PopupMenuRoute extends PopupRoute { this.shape, this.color, required this.capturedThemes, - required this.placement, }) : itemSizes = List.filled(items.length, null); final RelativeRect position; @@ -742,7 +714,6 @@ class _PopupMenuRoute extends PopupRoute { final ShapeBorder? shape; final Color? color; final CapturedThemes capturedThemes; - final PopupMenuPlacement placement; @override Animation createAnimation() { @@ -778,22 +749,20 @@ class _PopupMenuRoute extends PopupRoute { final Widget menu = _PopupMenu(route: this, semanticLabel: semanticLabel); - return Builder( - builder: (BuildContext context) { - final MediaQueryData mediaQuery = MediaQuery.of(context); - return CustomSingleChildLayout( - delegate: _PopupMenuRouteLayout( - position, - itemSizes, - selectedItemIndex, - Directionality.of(context), - mediaQuery.padding.top, - mediaQuery.padding.bottom, - placement, - ), - child: capturedThemes.wrap(menu), - ); - }, + return SafeArea( + child: Builder( + builder: (BuildContext context) { + return CustomSingleChildLayout( + delegate: _PopupMenuRouteLayout( + position, + itemSizes, + selectedItemIndex, + Directionality.of(context), + ), + child: capturedThemes.wrap(menu), + ); + }, + ), ); } } @@ -863,7 +832,6 @@ Future showMenu({ ShapeBorder? shape, Color? color, bool useRootNavigator = false, - PopupMenuPlacement placement = PopupMenuPlacement.aboveButton, }) { assert(context != null); assert(position != null); @@ -893,7 +861,6 @@ Future showMenu({ shape: shape, color: color, capturedThemes: InheritedTheme.capture(from: context, to: navigator.context), - placement: placement, )); } @@ -916,17 +883,6 @@ typedef PopupMenuCanceled = void Function(); /// Used by [PopupMenuButton.itemBuilder]. typedef PopupMenuItemBuilder = List> Function(BuildContext context); -/// The placement of the menu popped up by press the [PopupMenuButton]. -/// -/// Used by [PopupMenuButton.placement]. -enum PopupMenuPlacement { - /// The popup menu is positioned above the button that generates it. - aboveButton, - - /// The popup menu is positioned below the button that generates it. - belowButton, -} - /// Displays a menu when pressed and calls [onSelected] when the menu is dismissed /// because an item was selected. The value passed to [onSelected] is the value of /// the selected menu item. @@ -999,7 +955,6 @@ class PopupMenuButton extends StatefulWidget { this.shape, this.color, this.enableFeedback, - this.placement = PopupMenuPlacement.aboveButton, }) : assert(itemBuilder != null), assert(offset != null), assert(enabled != null), @@ -1051,7 +1006,7 @@ class PopupMenuButton extends StatefulWidget { /// The offset applied to the Popup Menu Button. /// - /// When not set, the Popup Menu Button will be positioned directly below + /// When not set, the Popup Menu Button will be positioned directly next to /// the button that was used to create it. final Offset offset; @@ -1094,11 +1049,6 @@ class PopupMenuButton extends StatefulWidget { /// * [Feedback] for providing platform-specific feedback to certain actions. final bool? enableFeedback; - /// The placement of the menu popped up by press the [PopupMenuButton]. - /// - /// Default to [PopupMenuPlacement.aboveButton]. - final PopupMenuPlacement placement; - /// If provided, the size of the [Icon]. /// /// If this property is null, the default size is 24.0 pixels. @@ -1113,9 +1063,8 @@ class PopupMenuButton extends StatefulWidget { /// See [showButtonMenu] for a way to programmatically open the popup menu /// of your button state. class PopupMenuButtonState extends State> { - final GlobalKey _menuButtonKey = GlobalKey(); /// A method to show a popup menu with the items supplied to - /// [PopupMenuButton.itemBuilder] at the position below your [PopupMenuButton]. + /// [PopupMenuButton.itemBuilder] at the position of your [PopupMenuButton]. /// /// By default, it is called when the user taps the button and [PopupMenuButton.enabled] /// is set to `true`. Moreover, you can open the button by calling the method manually. @@ -1124,14 +1073,8 @@ class PopupMenuButtonState extends State> { /// show the menu of the button with `globalKey.currentState.showButtonMenu`. void showButtonMenu() { final PopupMenuThemeData popupMenuTheme = PopupMenuTheme.of(context); + final RenderBox button = context.findRenderObject()! as RenderBox; final RenderBox overlay = Navigator.of(context).overlay!.context.findRenderObject()! as RenderBox; - final RenderBox button; - if (widget.placement == PopupMenuPlacement.belowButton) { - button = _menuButtonKey.currentContext!.findRenderObject()! as RenderBox; - } else { - // Backward compatible. - button = context.findRenderObject()! as RenderBox; - } final RelativeRect position = RelativeRect.fromRect( Rect.fromPoints( button.localToGlobal(widget.offset, ancestor: overlay), @@ -1150,7 +1093,6 @@ class PopupMenuButtonState extends State> { position: position, shape: widget.shape ?? popupMenuTheme.shape, color: widget.color ?? popupMenuTheme.color, - placement: widget.placement, ) .then((T? newValue) { if (!mounted) @@ -1190,40 +1132,18 @@ class PopupMenuButtonState extends State> { child: InkWell( onTap: widget.enabled ? showButtonMenu : null, canRequestFocus: _canRequestFocus, + child: widget.child, enableFeedback: enableFeedback, - child: LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - return UnconstrainedBox( - constrainedAxis: Axis.horizontal, - child: LimitedBox( - key: _menuButtonKey, - maxHeight: constraints.maxHeight, - child: widget.child, - ), - ); - }, - ), ), ); - return LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - return UnconstrainedBox( - constrainedAxis: Axis.horizontal, - child: LimitedBox( - maxHeight: constraints.maxHeight, - child: IconButton( - key: _menuButtonKey, - icon: widget.icon ?? Icon(Icons.adaptive.more), - padding: widget.padding, - iconSize: widget.iconSize ?? 24.0, - tooltip: widget.tooltip ?? MaterialLocalizations.of(context).showMenuTooltip, - onPressed: widget.enabled ? showButtonMenu : null, - enableFeedback: enableFeedback, - ), - ), - ); - }, + return IconButton( + icon: widget.icon ?? Icon(Icons.adaptive.more), + padding: widget.padding, + iconSize: widget.iconSize ?? 24.0, + tooltip: widget.tooltip ?? MaterialLocalizations.of(context).showMenuTooltip, + onPressed: widget.enabled ? showButtonMenu : null, + enableFeedback: enableFeedback, ); } } diff --git a/packages/flutter/test/material/popup_menu_test.dart b/packages/flutter/test/material/popup_menu_test.dart index 4785d1c17d..713907474f 100644 --- a/packages/flutter/test/material/popup_menu_test.dart +++ b/packages/flutter/test/material/popup_menu_test.dart @@ -453,7 +453,6 @@ void main() { testWidgets('PopupMenu positioning', (WidgetTester tester) async { final Widget testButton = PopupMenuButton( - placement: PopupMenuPlacement.belowButton, itemBuilder: (BuildContext context) { return >[ const PopupMenuItem(value: 1, child: Text('AAA')), @@ -619,24 +618,24 @@ void main() { }); } - await testPositioningDown(tester, TextDirection.ltr, Alignment.topRight, TextDirection.rtl, const Rect.fromLTWH(792.0, 100.0, 0.0, 0.0)); - await testPositioningDown(tester, TextDirection.rtl, Alignment.topRight, TextDirection.rtl, const Rect.fromLTWH(792.0, 100.0, 0.0, 0.0)); - await testPositioningDown(tester, TextDirection.ltr, Alignment.topLeft, TextDirection.ltr, const Rect.fromLTWH(8.0, 100.0, 0.0, 0.0)); - await testPositioningDown(tester, TextDirection.rtl, Alignment.topLeft, TextDirection.ltr, const Rect.fromLTWH(8.0, 100.0, 0.0, 0.0)); - await testPositioningDown(tester, TextDirection.ltr, Alignment.topCenter, TextDirection.ltr, const Rect.fromLTWH(350.0, 100.0, 0.0, 0.0)); - await testPositioningDown(tester, TextDirection.rtl, Alignment.topCenter, TextDirection.rtl, const Rect.fromLTWH(450.0, 100.0, 0.0, 0.0)); - await testPositioningDown(tester, TextDirection.ltr, Alignment.centerRight, TextDirection.rtl, const Rect.fromLTWH(792.0, 350.0, 0.0, 0.0)); - await testPositioningDown(tester, TextDirection.rtl, Alignment.centerRight, TextDirection.rtl, const Rect.fromLTWH(792.0, 350.0, 0.0, 0.0)); - await testPositioningDown(tester, TextDirection.ltr, Alignment.centerLeft, TextDirection.ltr, const Rect.fromLTWH(8.0, 350.0, 0.0, 0.0)); - await testPositioningDown(tester, TextDirection.rtl, Alignment.centerLeft, TextDirection.ltr, const Rect.fromLTWH(8.0, 350.0, 0.0, 0.0)); - await testPositioningDown(tester, TextDirection.ltr, Alignment.center, TextDirection.ltr, const Rect.fromLTWH(350.0, 350.0, 0.0, 0.0)); - await testPositioningDown(tester, TextDirection.rtl, Alignment.center, TextDirection.rtl, const Rect.fromLTWH(450.0, 350.0, 0.0, 0.0)); - await testPositioningDownThenUp(tester, TextDirection.ltr, Alignment.bottomRight, TextDirection.rtl, const Rect.fromLTWH(792.0, 592.0, 0.0, 0.0)); - await testPositioningDownThenUp(tester, TextDirection.rtl, Alignment.bottomRight, TextDirection.rtl, const Rect.fromLTWH(792.0, 592.0, 0.0, 0.0)); - await testPositioningDownThenUp(tester, TextDirection.ltr, Alignment.bottomLeft, TextDirection.ltr, const Rect.fromLTWH(8.0, 592.0, 0.0, 0.0)); - await testPositioningDownThenUp(tester, TextDirection.rtl, Alignment.bottomLeft, TextDirection.ltr, const Rect.fromLTWH(8.0, 592.0, 0.0, 0.0)); - await testPositioningDownThenUp(tester, TextDirection.ltr, Alignment.bottomCenter, TextDirection.ltr, const Rect.fromLTWH(350.0, 592.0, 0.0, 0.0)); - await testPositioningDownThenUp(tester, TextDirection.rtl, Alignment.bottomCenter, TextDirection.rtl, const Rect.fromLTWH(450.0, 592.0, 0.0, 0.0)); + await testPositioningDown(tester, TextDirection.ltr, Alignment.topRight, TextDirection.rtl, const Rect.fromLTWH(792.0, 8.0, 0.0, 0.0)); + await testPositioningDown(tester, TextDirection.rtl, Alignment.topRight, TextDirection.rtl, const Rect.fromLTWH(792.0, 8.0, 0.0, 0.0)); + await testPositioningDown(tester, TextDirection.ltr, Alignment.topLeft, TextDirection.ltr, const Rect.fromLTWH(8.0, 8.0, 0.0, 0.0)); + await testPositioningDown(tester, TextDirection.rtl, Alignment.topLeft, TextDirection.ltr, const Rect.fromLTWH(8.0, 8.0, 0.0, 0.0)); + await testPositioningDown(tester, TextDirection.ltr, Alignment.topCenter, TextDirection.ltr, const Rect.fromLTWH(350.0, 8.0, 0.0, 0.0)); + await testPositioningDown(tester, TextDirection.rtl, Alignment.topCenter, TextDirection.rtl, const Rect.fromLTWH(450.0, 8.0, 0.0, 0.0)); + await testPositioningDown(tester, TextDirection.ltr, Alignment.centerRight, TextDirection.rtl, const Rect.fromLTWH(792.0, 250.0, 0.0, 0.0)); + await testPositioningDown(tester, TextDirection.rtl, Alignment.centerRight, TextDirection.rtl, const Rect.fromLTWH(792.0, 250.0, 0.0, 0.0)); + await testPositioningDown(tester, TextDirection.ltr, Alignment.centerLeft, TextDirection.ltr, const Rect.fromLTWH(8.0, 250.0, 0.0, 0.0)); + await testPositioningDown(tester, TextDirection.rtl, Alignment.centerLeft, TextDirection.ltr, const Rect.fromLTWH(8.0, 250.0, 0.0, 0.0)); + await testPositioningDown(tester, TextDirection.ltr, Alignment.center, TextDirection.ltr, const Rect.fromLTWH(350.0, 250.0, 0.0, 0.0)); + await testPositioningDown(tester, TextDirection.rtl, Alignment.center, TextDirection.rtl, const Rect.fromLTWH(450.0, 250.0, 0.0, 0.0)); + await testPositioningDownThenUp(tester, TextDirection.ltr, Alignment.bottomRight, TextDirection.rtl, const Rect.fromLTWH(792.0, 500.0, 0.0, 0.0)); + await testPositioningDownThenUp(tester, TextDirection.rtl, Alignment.bottomRight, TextDirection.rtl, const Rect.fromLTWH(792.0, 500.0, 0.0, 0.0)); + await testPositioningDownThenUp(tester, TextDirection.ltr, Alignment.bottomLeft, TextDirection.ltr, const Rect.fromLTWH(8.0, 500.0, 0.0, 0.0)); + await testPositioningDownThenUp(tester, TextDirection.rtl, Alignment.bottomLeft, TextDirection.ltr, const Rect.fromLTWH(8.0, 500.0, 0.0, 0.0)); + await testPositioningDownThenUp(tester, TextDirection.ltr, Alignment.bottomCenter, TextDirection.ltr, const Rect.fromLTWH(350.0, 500.0, 0.0, 0.0)); + await testPositioningDownThenUp(tester, TextDirection.rtl, Alignment.bottomCenter, TextDirection.rtl, const Rect.fromLTWH(450.0, 500.0, 0.0, 0.0)); }); testWidgets('PopupMenu positioning inside nested Overlay', (WidgetTester tester) async { @@ -654,7 +653,6 @@ void main() { builder: (_) => Center( child: PopupMenuButton( key: buttonKey, - placement: PopupMenuPlacement.belowButton, itemBuilder: (_) => >[ const PopupMenuItem(value: 1, child: Text('Item 1')), const PopupMenuItem(value: 2, child: Text('Item 2')), @@ -675,8 +673,8 @@ void main() { await tester.tap(buttonFinder); await tester.pumpAndSettle(); - final Offset buttonBottomLeft = tester.getBottomLeft(buttonFinder); - expect(tester.getTopLeft(popupFinder), buttonBottomLeft); + final Offset buttonTopLeft = tester.getTopLeft(buttonFinder); + expect(tester.getTopLeft(popupFinder), buttonTopLeft); }); testWidgets('PopupMenu positioning inside nested Navigator', (WidgetTester tester) async { @@ -697,7 +695,6 @@ void main() { child: Center( child: PopupMenuButton( key: buttonKey, - placement: PopupMenuPlacement.belowButton, itemBuilder: (_) => >[ const PopupMenuItem(value: 1, child: Text('Item 1')), const PopupMenuItem(value: 2, child: Text('Item 2')), @@ -720,8 +717,8 @@ void main() { await tester.tap(buttonFinder); await tester.pumpAndSettle(); - final Offset buttonBottomLeft = tester.getBottomLeft(buttonFinder); - expect(tester.getTopLeft(popupFinder), buttonBottomLeft); + final Offset buttonTopLeft = tester.getTopLeft(buttonFinder); + expect(tester.getTopLeft(popupFinder), buttonTopLeft); }); testWidgets('PopupMenu removes MediaQuery padding', (WidgetTester tester) async { @@ -734,7 +731,6 @@ void main() { ), child: Material( child: PopupMenuButton( - placement: PopupMenuPlacement.belowButton, itemBuilder: (BuildContext context) { popupContext = context; return >[ @@ -769,7 +765,6 @@ void main() { testWidgets('Popup Menu Offset Test', (WidgetTester tester) async { PopupMenuButton buildMenuButton({Offset offset = Offset.zero}) { return PopupMenuButton( - placement: PopupMenuPlacement.belowButton, offset: offset, itemBuilder: (BuildContext context) { return >[ @@ -801,10 +796,8 @@ void main() { await tester.tap(find.byType(IconButton)); await tester.pumpAndSettle(); - final Size iconSize = tester.getSize(find.byType(IconButton)); - - // Initial state, the menu start at bottomLeft of the icon, the 8 pixels is edge padding when offset.dx < 8.0. - expect(tester.getTopLeft(find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_PopupMenu')), Offset(8.0, iconSize.height)); + // Initial state, the menu start at Offset(8.0, 8.0), the 8 pixels is edge padding when offset.dx < 8.0. + expect(tester.getTopLeft(find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_PopupMenu')), const Offset(8.0, 8.0)); // Collapse the menu. await tester.tap(find.byType(IconButton), warnIfMissed: false); @@ -824,8 +817,8 @@ void main() { await tester.tap(find.byType(IconButton)); await tester.pumpAndSettle(); - // This time the menu should start at Offset(50.0, 50.0 + iconSize.height), the padding only added when offset.dx < 8.0. - expect(tester.getTopLeft(find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_PopupMenu')), Offset(50.0, 50.0 + iconSize.height)); + // This time the menu should start at Offset(50.0, 50.0), the padding only added when offset.dx < 8.0. + expect(tester.getTopLeft(find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_PopupMenu')), const Offset(50.0, 50.0)); }); testWidgets('open PopupMenu has correct semantics', (WidgetTester tester) async { @@ -1811,124 +1804,6 @@ void main() { ); }); - testWidgets('PopupMenu button can render at its "natural" size in AppBar', (WidgetTester tester) async { - final GlobalKey buttonKey = GlobalKey(); - - Widget buildFrame(double width, double height) { - return MaterialApp( - builder: (BuildContext context, Widget? child) { - return MediaQuery( - data: const MediaQueryData( - padding: EdgeInsets.only( - top: 32.0, - bottom: 32.0, - ), - ), - child: child!, - ); - }, - home: Scaffold( - appBar: AppBar( - toolbarHeight: 100.0, - title: const Text('PopupMenu Test'), - actions: [PopupMenuButton( - child: SizedBox( - key: buttonKey, - height: height, - width: width, - child: const ColoredBox( - color: Colors.pink, - ), - ), - itemBuilder: (BuildContext context) => >[ - const PopupMenuItem(child: Text('-1-'), value: 1), - const PopupMenuItem(child: Text('-2-'), value: 2), - const PopupMenuItem(child: Text('-3-'), value: 3), - const PopupMenuItem(child: Text('-4-'), value: 4), - const PopupMenuItem(child: Text('-5-'), value: 5), - ], - )], - ), - body: Container(), - ), - ); - } - - await tester.pumpWidget(buildFrame(10.0, 10.0)); - Size buttonSize = tester.getSize(find.byKey(buttonKey)); - expect(buttonSize, const Size(10.0, 10.0)); - - await tester.pumpWidget(buildFrame(20.5, 30.5)); - buttonSize = tester.getSize(find.byKey(buttonKey)); - expect(buttonSize, const Size(20.5, 30.5)); - - await tester.pumpWidget(buildFrame(20.0, 100.0)); - buttonSize = tester.getSize(find.byKey(buttonKey)); - expect(buttonSize, const Size(20.0, 100.0)); - - await tester.pumpWidget(buildFrame(20.0, 100.1)); - buttonSize = tester.getSize(find.byKey(buttonKey)); - expect(buttonSize, const Size(20.0, 100.0)); // Do not overflow the AppBar. - }); - - testWidgets('PopupMenu position test when have unsafe area', (WidgetTester tester) async { - final GlobalKey buttonKey = GlobalKey(); - final GlobalKey firstItemKey = GlobalKey(); - - Widget buildFrame(double width, double height) { - return MaterialApp( - builder: (BuildContext context, Widget? child) { - return MediaQuery( - data: const MediaQueryData( - padding: EdgeInsets.only( - top: 32.0, - bottom: 32.0, - ), - ), - child: child!, - ); - }, - home: Scaffold( - appBar: AppBar( - title: const Text('PopupMenu Test'), - actions: [PopupMenuButton( - placement: PopupMenuPlacement.belowButton, - child: SizedBox( - key: buttonKey, - height: height, - width: width, - child: const ColoredBox( - color: Colors.pink, - ), - ), - itemBuilder: (BuildContext context) => >[ - PopupMenuItem( - key: firstItemKey, - child: const Text('-1-'), - value: 1, - ), - const PopupMenuItem(child: Text('-2-'), value: 2,), - ], - )], - ), - body: Container(), - ), - ); - } - - await tester.pumpWidget(buildFrame(20.0, 20.0)); - - await tester.tap(find.byKey(buttonKey)); - await tester.pumpAndSettle(); - - final Offset button = tester.getBottomRight(find.byKey(buttonKey)); - final Offset popupMenu = tester.getTopRight(find.byKey(firstItemKey)); - - // The menu should popup below the button. - // The 8.0 pixels are [_kMenuScreenPadding] and [_kMenuVerticalPadding]. - expect(popupMenu, Offset(button.dx - 8.0, button.dy + 8.0)); - }); - group('feedback', () { late FeedbackTester feedback; diff --git a/packages/flutter_localizations/test/text_test.dart b/packages/flutter_localizations/test/text_test.dart index bd0e002cfb..81edc7a12b 100644 --- a/packages/flutter_localizations/test/text_test.dart +++ b/packages/flutter_localizations/test/text_test.dart @@ -38,7 +38,6 @@ void main() { key: targetKey, builder: (BuildContext context) { return PopupMenuButton( - placement: PopupMenuPlacement.belowButton, onSelected: (int value) { Navigator.pushNamed(context, '/next'); }, @@ -79,20 +78,20 @@ void main() { Offset bottomLeft = tester.getBottomLeft(find.text('hello, world')); Offset bottomRight = tester.getBottomRight(find.text('hello, world')); - expect(topLeft, const Offset(392.0, 347.5)); - expect(topRight, const Offset(596.0, 347.5)); - expect(bottomLeft, const Offset(392.0, 364.5)); - expect(bottomRight, const Offset(596.0, 364.5)); + expect(topLeft, const Offset(392.0, 299.5)); + expect(topRight, const Offset(596.0, 299.5)); + expect(bottomLeft, const Offset(392.0, 316.5)); + expect(bottomRight, const Offset(596.0, 316.5)); topLeft = tester.getTopLeft(find.text('你好,世界')); topRight = tester.getTopRight(find.text('你好,世界')); bottomLeft = tester.getBottomLeft(find.text('你好,世界')); bottomRight = tester.getBottomRight(find.text('你好,世界')); - expect(topLeft, const Offset(392.0, 395.5)); - expect(topRight, const Offset(477.0, 395.5)); - expect(bottomLeft, const Offset(392.0, 412.5)); - expect(bottomRight, const Offset(477.0, 412.5)); + expect(topLeft, const Offset(392.0, 347.5)); + expect(topRight, const Offset(477.0, 347.5)); + expect(bottomLeft, const Offset(392.0, 364.5)); + expect(bottomRight, const Offset(477.0, 364.5)); }); testWidgets('Text baseline with EN locale', (WidgetTester tester) async { @@ -125,7 +124,6 @@ void main() { key: targetKey, builder: (BuildContext context) { return PopupMenuButton( - placement: PopupMenuPlacement.belowButton, onSelected: (int value) { Navigator.pushNamed(context, '/next'); }, @@ -166,19 +164,19 @@ void main() { Offset bottomLeft = tester.getBottomLeft(find.text('hello, world')); Offset bottomRight = tester.getBottomRight(find.text('hello, world')); - expect(topLeft, const Offset(392.0, 348.0)); - expect(topRight, const Offset(584.0, 348.0)); - expect(bottomLeft, const Offset(392.0, 364)); - expect(bottomRight, const Offset(584.0, 364)); + expect(topLeft, const Offset(392.0, 300.0)); + expect(topRight, const Offset(584.0, 300.0)); + expect(bottomLeft, const Offset(392.0, 316)); + expect(bottomRight, const Offset(584.0, 316)); topLeft = tester.getTopLeft(find.text('你好,世界')); topRight = tester.getTopRight(find.text('你好,世界')); bottomLeft = tester.getBottomLeft(find.text('你好,世界')); bottomRight = tester.getBottomRight(find.text('你好,世界')); - expect(topLeft, const Offset(392.0, 396.0)); - expect(topRight, const Offset(472.0, 396.0)); - expect(bottomLeft, const Offset(392.0, 412.0)); - expect(bottomRight, const Offset(472.0, 412.0)); + expect(topLeft, const Offset(392.0, 348.0)); + expect(topRight, const Offset(472.0, 348.0)); + expect(bottomLeft, const Offset(392.0, 364.0)); + expect(bottomRight, const Offset(472.0, 364.0)); }); }