Does anyone know why the PopupMenuButton renders at the wrong place when used in a ReorderableListView? It seems to render correctly when used inside a normal ListView.
Here is an example screenshot:
For those that want example code:
import 'package:flutter/material.dart';
void main() {
runApp(ListApp());
}
class ListApp extends StatefulWidget {
@override
_ListAppState createState() => _ListAppState();
}
class _ListAppState extends State<ListApp> {
List<String> items = [
"Item 1",
"Item 2",
"Item 3",
"Item 4",
"Item 5",
"Item 6",
"Item 7",
];
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Reorder List'),
),
body: Container(
child: ReorderableListView(
// child: ListView(
onReorder: (oldIndex, newIndex) {
int deleteIndex = oldIndex;
items.insert(newIndex, items[oldIndex]);
if (oldIndex > newIndex) {
// The old index is now 1 index higher
deleteIndex++;
}
items.removeAt(deleteIndex);
setState(() {
items = items;
});
},
children: items.map((item) {
return Card(
key: Key(item),
child: ListTile(
title: Text(item),
trailing: PopupMenuButton(
itemBuilder: (context) {
return [
PopupMenuItem(
child: Text(item),
value: item,
)
];
},
),
),
);
}).toList()),
),
),
);
}
}
Could it be that I'm using the PopupMenuButton the wrong way or is this Widget buggy?
I'd like my list to be sortable but the PopupMenuButton appearing at the wrong place is a problem.
It seems that the problem should be in the ReorderableListView widget's code, but in fact it's hidden in PopupMenu. To calculate popup position this code evaluates overlay's rendering box:
final RenderBox overlay = Overlay.of(context).context.findRenderObject() as RenderBox;
Because, by default, the Overlay.of
method searches hierarchy for the nearest overlay, in case of ReorderableListView it returns internal overlay (one created to restrict dragging gesture) but for ListView it returns root overlay. Since the root navigator used to show popup menu, a shift appears in the former case.
Calling Overlay.of
method with rootOverlay: true
fixes the bug:
final RenderBox overlay = Overlay.of(context, rootOverlay: true).context.findRenderObject() as RenderBox;
Patching Flutter SDK is the most appropriate solution.
I think this is as best as you can get it without tapping into the widget
PopupMenuButton(
offset: Offset(0, 50), //add offset to fix it
itemBuilder: (context) {
return [
PopupMenuItem(
child: Text(item),
value: item,
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With