¿Cómo abro un menú emergente desde un segundo widget?
final button = new PopupMenuButton( itemBuilder: (_) => <PopupMenuItem<String>>[ new PopupMenuItem<String>( child: const Text('Doge'), value: 'Doge'), new PopupMenuItem<String>( child: const Text('Lion'), value: 'Lion'), ], onSelected: _doSomething); final tile = new ListTile(title: new Text('Doge or lion?'), trailing: button); Quiero abrir el menú del button tocando el tile .
Esto funciona, pero no es elegante (y tiene el mismo problema de visualización que la solución de Rainer anterior:
class _MyHomePageState extends State<MyHomePage> { final GlobalKey _menuKey = GlobalKey(); @override Widget build(BuildContext context) { final button = PopupMenuButton( key: _menuKey, itemBuilder: (_) => const<PopupMenuItem<String>>[ PopupMenuItem<String>( child: Text('Doge'), value: 'Doge'), PopupMenuItem<String>( child: Text('Lion'), value: 'Lion'), ], onSelected: (_) {}); final tile = ListTile(title: Text('Doge or lion?'), trailing: button, onTap: () { // This is a hack because _PopupMenuButtonState is private. dynamic state = _menuKey.currentState; state.showButtonMenu(); }); return Scaffold( body: Center( child: tile, ), ); } }Sospecho que lo que realmente está pidiendo es algo así como lo que rastrea https://github.com/flutter/flutter/issues/254 o https://github.com/flutter/flutter/issues/8277 : el capacidad de asociar una etiqueta con un control y hacer que se pueda hacer clic en la etiqueta, y es una característica que falta en el marco Flutter.
Creo que sería mejor hacerlo de esta manera, en lugar de mostrar un PopupMenuButton
void _showPopupMenu() async { await showMenu( context: context, position: RelativeRect.fromLTRB(100, 100, 100, 100), items: [ PopupMenuItem<String>( child: const Text('Doge'), value: 'Doge'), PopupMenuItem<String>( child: const Text('Lion'), value: 'Lion'), ], elevation: 8.0, ); }Habrá momentos en los que desee mostrar _showPopupMenu en la ubicación donde presionó el botón Usar GestureDetector para eso
final tile = new ListTile( title: new Text('Doge or lion?'), trailing: GestureDetector( onTapDown: (TapDownDetails details) { _showPopupMenu(details.globalPosition); }, child: Container(child: Text("Press Me")), ), );y luego _showPopupMenu será como
_showPopupMenu(Offset offset) async { double left = offset.dx; double top = offset.dy; await showMenu( context: context, position: RelativeRect.fromLTRB(left, top, 0, 0), items: [ ..., elevation: 8.0, ); }Encontré una solución a tu pregunta. Puede proporcionar un elemento secundario a PopupMenuButton, que puede ser cualquier widget, incluido un ListTile (consulte el código a continuación). El único problema es que PopupMenu se abre en el lado izquierdo de ListTile.
final popupMenu = new PopupMenuButton( child: new ListTile( title: new Text('Doge or lion?'), trailing: const Icon(Icons.more_vert), ), itemBuilder: (_) => <PopupMenuItem<String>>[ new PopupMenuItem<String>( child: new Text('Doge'), value: 'Doge'), new PopupMenuItem<String>( child: new Text('Lion'), value: 'Lion'), ], onSelected: _doSomething, )