Focused Pop-Up Menu in Flutter 🐱‍🏍

Paras Jain
5 min readJun 19, 2020

Menus are one of the most widely used features in Application Development. Although Navigation/Drawer Menu, Bottom Bar Menu and Action Bar Menu are widely used, they are not as flexible as Context/Pop-Up Menus.

Context Menu appears usually on Long Press (for Mobile Devices) or Right Click (for Desktop or Web Apps). In this article, you will learn ways to create Context/Pop-Up Menus in Flutter Applications which appear on Long Press, alongside the item which is pressed and it blurs other content on that particular screen. Take a look….🧐

Let’s Jump into it…

Well, for ease of explanation i have a template application screen ready which looks like the one you see up in the example. Code looks something like this…

You can see that each item in the GridView Widget is a Card with an Image Widget for its child.

In simple words, the way we will approach creating this popup menu is by taking the widget which is long pressed and passing it to a New Screen and then displaying that New Screen on top of our previous screen with a Backdrop Filter. And the most crucial things that we need to get regarding the widget which is long pressed are:

  1. Location of that widget on the screen. (Global Co-ordinates)
  2. Size of that Widget (To Exactly overlap the main Screen Widget)
  3. Widget Itself (To Pass to the New Screen)

Let’s start by taking a look at how to get the location of the Widget that is Long Pressed. The best way to do this would be to wrap the target widget with a Custom Stateful Widget and then use that Stateful Widget to get location of its Child (Target Widget) using Global Key. This Stateful Widget that we have to create looks something like this:

In this Stateful Widget you can see that we have a required property of child and menuContent for that Widget and in the build function we wrap that child with a Gesture Detector with which we can detect the long press.

Now, as soon as the user long presses the child widget we use “getOffset” function that you can see on line 15 of the code above to get current information regarding that child widget. With this we get the current location of widget, size of that widget and we already have the target widget with us as a child in FocusedMenuHolder.

Now we have to wrap each GridView item with this FocusedMenuHolder and the code for GridView will now look like this:

Now that we have the target widget and all its necessary details, We need to Navigate to a New Screen with target widget and all its details passed as an argument and then show a popup/context menu on that New screen. With this we will also blur the background (ie Main Screen) using Backdrop Filter.

This task of Navigation has to be done from FocusedMenuHolder because we have access to Target Widget and its details only there. For this we won’t use the traditional MaterialPageRoute, but instead we will use PageRouteBuilder to customize the transition experience a bit and also to control the opacity of New Screen over the Main Screen. We will add code for this navigation in just a moment but before, we need to create that Second Screen where the Context/Popup Menu will be displayed. Let’s name this FocusedMenuDetails and take a look at its code:

You can see that here we are passing on properties like child, childOffset , childSize and menuContent. These will be passed from FocusedMenuHolder while Navigation. In the build function of FocusedMenuDetails (Second Screen) we have Stack so as to position all the elements like menu and child according to childOffset.

The first child of Stack is BackdropFilter wrapped by GestureDetector.

We need this gesture detector to detect if the user clicks on are surrounding the menu and then pop this screen out. This Backdrop filter is added as the first child only because backdrop filter Blurs out any content that is above it in the Stack. You can learn more about this here.

Second child of Stack is Positioned Widget to position the Menu on this screen.

The position calculated for this menu is from the top and left of the screen. You can see the calculation involved from lines 19–22 in the code above for FocusedMenuDetails file. We need to calculate these positions in such a way that the menu does not overflow the screen. By these calculations menu can be displayed on left,right,top or bottom depending upon the position of the Target Widget. Also the menuContent is wrapped by a TweenAnimationBuilder to add a bit of Animation when the menu appears.

The Third and the last child of this stack is the child widget itself.

We need to show this widget at the exact same position where it is on the main screen and this is possible with the help of childOffset that we receive. We pass in the exact positions that we get from this offset to Positioned and also wrap the child widget with a container for which we set a size using childSize. This is important so that the child widget does not resize itself being Boundless.

Okay Now! Most of the hard work is done…. 🤓🧾 Now we just need to Navigate to this new screen using FocusedMenuHolder. So the final code for FocusedMenuHolder looks like this:

The only update here is the addition of Navigator.push in the onLongPress function. Make sure to set fullscreenDialog property to “true” and opaque to “false” for PageRouteBuilder. Once this is added, the final app looks something like this:

Voila! 😎 Here we have a Focused Context Menu which displays whatever content you want on long press of target widget.

There can be a number of customization options that you can create for this and to simplify this whole process for you i have created a package for adding this Focused Pop-Up Menu to you application in an easy and convenient way!

You can take a look at that package here:

If you like the package! Make sure to rate it on pub.dev and star the git repository. Link is:

I have been creating a lot of UI Packages lately and i would like you to take a look at my Git and pub.dev profile for all of them. Feel free to Leave your reviews and suggestions, i will take them in account to for future updates to these package and create my future Packages accordingly!

I hope you find this article useful and if you do make sure to check out my channel @RetroPortalStuio on YouTube. Happy Coding! ✌😁

Twitter: https://www.twitter.com/theretroportal

Instagram: https://www.instagram.com/retroportalstudio

LinkedIn: https://www.linkedin.com/in/parasjainrps Happy Coding! ✌️😁

--

--

Paras Jain

Mobile Application and Web Developer | @Youtube Content Creator | Worship #reactjs #flutter #java #dart | youtube.com/retroportalstudio