From f44b277fa632c848ea113ee3f397f713bc429153 Mon Sep 17 00:00:00 2001 From: jslavitz Date: Wed, 3 Oct 2018 11:19:19 -0700 Subject: [PATCH] Custom offset functionality for Popup Menu Button (#22534) * Adds offset functionality to popup menu * Adds a test --- .../flutter/lib/src/material/popup_menu.dart | 10 ++++- .../test/material/popup_menu_test.dart | 39 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/material/popup_menu.dart b/packages/flutter/lib/src/material/popup_menu.dart index 83808d1ebc..74bfb99584 100644 --- a/packages/flutter/lib/src/material/popup_menu.dart +++ b/packages/flutter/lib/src/material/popup_menu.dart @@ -820,7 +820,9 @@ class PopupMenuButton extends StatefulWidget { this.padding = const EdgeInsets.all(8.0), this.child, this.icon, + this.offset = Offset.zero, }) : assert(itemBuilder != null), + assert(offset != null), assert(!(child != null && icon != null)), // fails if passed both parameters super(key: key); @@ -864,6 +866,12 @@ class PopupMenuButton extends StatefulWidget { /// If provided, the icon used for this button. final Icon icon; + /// The offset applied to the Popup Menu Button. + /// + /// When not set, the Popup Menu Button will be positioned directly next to + /// the button that was used to create it. + final Offset offset; + @override _PopupMenuButtonState createState() => _PopupMenuButtonState(); } @@ -874,7 +882,7 @@ class _PopupMenuButtonState extends State> { final RenderBox overlay = Overlay.of(context).context.findRenderObject(); final RelativeRect position = RelativeRect.fromRect( Rect.fromPoints( - button.localToGlobal(Offset.zero, ancestor: overlay), + button.localToGlobal(widget.offset, ancestor: overlay), button.localToGlobal(button.size.bottomRight(Offset.zero), ancestor: overlay), ), Offset.zero & overlay.size, diff --git a/packages/flutter/test/material/popup_menu_test.dart b/packages/flutter/test/material/popup_menu_test.dart index f6d6d2aa88..3352a7bb2c 100644 --- a/packages/flutter/test/material/popup_menu_test.dart +++ b/packages/flutter/test/material/popup_menu_test.dart @@ -430,6 +430,45 @@ void main() { expect(MediaQuery.of(popupContext).padding, EdgeInsets.zero); }); + testWidgets('Popup Menu Offset Test', (WidgetTester tester) async { + const Offset offset = Offset(100.0, 100.0); + + final PopupMenuButton popupMenuButton = + PopupMenuButton( + offset: offset, + itemBuilder: (BuildContext context) { + return >[ + PopupMenuItem( + value: 1, + child: Builder( + builder: (BuildContext context) { + return const Text('AAA'); + }, + ), + ), + ]; + }, + ); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: Center( + child: Material( + child: popupMenuButton, + ), + ) + ), + ), + ); + + await tester.tap(find.byType(IconButton)); + await tester.pumpAndSettle(); + + // The position is different than the offset because the default position isn't at the origin. + expect(tester.getTopLeft(find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_PopupMenu')), const Offset(364.0, 324.0)); + }); + testWidgets('open PopupMenu has correct semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(MaterialApp(