Hi Guys, Welcome to Proto Coders Point. In this Flutter article let’s learn how to show popup menu item on long press on a widget.
There might be a requirement in flutter app development. i.e. when a user long press on a widget we should show a context menu item, & the position of flutter popup menu should be near by the long tapped location of the screen.
Video Tutorial
Flutter popup menu on long press
To get screen tapped position i.e. X & Y Coordinates will make use of a widget called as GestureDetector. You just need to wrap a widget with GestureDetector on which user can long press to get popup context menu near to the tapped position.
Snippet Code:
GestureDetector( onTapDown: (position)=>{ _getTapPosition(position) /* get screen tap position */ },onLongPress: ()=>{ _showContextMenu(context) /* action on long press }, child: Image.network('https://images.pexels.com/photos/674010/pexels-photo-674010.jpeg?cs=srgb&dl=pexels-anjana-c-674010.jpg&fm=jpg',width: 300,height: 300,) )
Function – Flutter Get Tap position X & Y Coordinates
The below function will help us in getting user tap position i.e. X & Y coordinate of our mobile screen.
Snippet Code:
void _getTapPosition(TapDownDetails tapPosition){ final RenderBox referenceBox = context.findRenderObject() as RenderBox; setState(() { _tapPosition = referenceBox.globalToLocal(tapPosition.globalPosition); // store the tap positon in offset variable print(_tapPosition); }); }
Flutter popup menu on long press at tap position
The below function will show a popup context menu item at long press position on the screen.
In out function, will use a in-built function i.e. showMenu that will help use in showing context menu items.
In showMenu function, we need to pass 3 parameter:
- context:
- position: /* position where user have long pressed to load popup menu items. /*
- items: /* list of popupmenuItem */
Menu function snippet code
Snippet Code:
void _showContextMenu(BuildContext context) async { final RenderObject? overlay = Overlay.of(context)?.context.findRenderObject(); final result = await showMenu( context: context, position: RelativeRect.fromRect( Rect.fromLTWH(_tapPosition.dx, _tapPosition.dy, 100, 100), Rect.fromLTWH(0, 0, overlay!.paintBounds.size.width, overlay!.paintBounds.size.height)), items: [ const PopupMenuItem( child: Text('Add Me'), value: "fav", ), const PopupMenuItem( child: Text('Close'), value: "close", ) ]); // perform action on selected menu item switch (result) { case 'fav': print("fav"); break; case 'close': print('close'); Navigator.pop(context); break; } }
Flutter show popup context menu near long press position
Will keep it simple. Will have a Image Widget at the center of screen, The Image Widget is been wrapped with GestureDetector therefore, When user long press on image widget we get the tap position using onTapDown() & onLongPress() will popup a context menu items which 2 options (Add to favorite & a Close menu).
Complete Source Code
main.dart
import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: const MyHomePage(), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({Key? key}) : super(key: key); @override State<MyHomePage> createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { Offset _tapPosition = Offset.zero; void _getTapPosition(TapDownDetails tapPosition) { final RenderBox referenceBox = context.findRenderObject() as RenderBox; setState(() { _tapPosition = referenceBox.globalToLocal(tapPosition.globalPosition); print(_tapPosition); }); } void _showContextMenu(BuildContext context) async { final RenderObject? overlay = Overlay.of(context)?.context.findRenderObject(); final result = await showMenu( context: context, position: RelativeRect.fromRect( Rect.fromLTWH(_tapPosition.dx, _tapPosition.dy, 100, 100), Rect.fromLTWH(0, 0, overlay!.paintBounds.size.width, overlay!.paintBounds.size.height)), items: [ const PopupMenuItem( child: Text('Add Me'), value: "fav", ), const PopupMenuItem( child: Text('Close'), value: "close", ) ]); // perform action on selected menu item switch (result) { case 'fav': print("fav"); break; case 'close': print('close'); Navigator.pop(context); break; } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('ProtoCodersPoint.com'), centerTitle: true, ), body: Padding( padding: const EdgeInsets.all(8.0), child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ GestureDetector( onTapDown: (position) => {_getTapPosition(position)}, onLongPress: () => {_showContextMenu(context)}, onDoubleTap: () => {_showContextMenu(context)}, child: Image.network( 'https://images.pexels.com/photos/674010/pexels-photo-674010.jpeg?cs=srgb&dl=pexels-anjana-c-674010.jpg&fm=jpg', width: 300, height: 300, )) ], ), ), )); } }