Custom offset functionality for Popup Menu Button (#22534)

* Adds offset functionality to popup menu
* Adds a test
This commit is contained in:
jslavitz 2018-10-03 11:19:19 -07:00 committed by GitHub
parent aa6a27e8a2
commit f44b277fa6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 48 additions and 1 deletions

View File

@ -820,7 +820,9 @@ class PopupMenuButton<T> 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<T> 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<T> createState() => _PopupMenuButtonState<T>();
}
@ -874,7 +882,7 @@ class _PopupMenuButtonState<T> extends State<PopupMenuButton<T>> {
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,

View File

@ -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<int> popupMenuButton =
PopupMenuButton<int>(
offset: offset,
itemBuilder: (BuildContext context) {
return <PopupMenuItem<int>>[
PopupMenuItem<int>(
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<int>')), const Offset(364.0, 324.0));
});
testWidgets('open PopupMenu has correct semantics', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester);
await tester.pumpWidget(MaterialApp(