Custom DropDown Menu in Flutter

shubham Gupta
4 min readApr 16, 2020

--

Hi Folks,

Wouldn’t it be interesting if our app would look a bit artistic? If that’s a yes then I am glad to come up with some new fascinating ideas. The drop-down menu is one of them. Today we will try to replicate the shown design in flutter. The design is picked from dribbble and is made by Zach Roszczewski.

Simple Account Menu|Dropdown by Zach Roszczewski

Here we will be using overlay entry to create an overlay on the screen when the menu button is pressed. You can read more about Overlay on the flutter docs.

For the menu button, we can use a simple icon button from flutter and wrap it with a container to make it look like the design. We use a GlobalKey here for the container whose use I will explain below.

Container(
key:_key,
decoration:BoxDecoration(
color:Color(0xFFF5C6373),
borderRadius:BorderRadius.circular(4),
),
child:IconButton(
icon:Icon(Icons.menu),
color:Colors.white,
onPressed:(){}
),
)

So once we have made the button the next step is to create a menu that will be shown when the button is pressed. Here we use a list of icons to show ie. icon of person, settings and credit card. Here the button size is the height and width of the menu button that we had created above. We will be using the same width and height to match the design.

List<Icon> icons =[
Icon(Icons.person),
Icon(Icons.settings),
Icon(Icons.credit_card),
];
Container(
height: icons.length * buttonSize.height,
decoration: BoxDecoration(
color: Color(0xFFF67C0B9),
borderRadius:BorderRadius.circular(4),
),
child: Theme(
data: ThemeData(
iconTheme: IconThemeData(
color:Colors.white,
),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children:List.generate(
icons.length,
(index){
return GestureDetector(
onTap: () {},
child: Container(
width: buttonSize.width,
height: buttonSize.height,
child: icons[index],
),
);
},
),
),
),
)

Once the menu button and the drop-down menu are ready we will now work on creating the overlay to show the drop-down menu when the button is pressed. Now the question arises on how and where to show the drop-down menu.

Now let us define some variables that will hold this important data for us like the button’s position, button’s size, and an OverlayEntry. We use the overlay entry variable so that we can easily insert the overlay ie. our drop-down menu and remove it whenever required. We will use a boolean to keep track of our menu whether it’s open or closed.

GlobalKey _key = LabeledGlobalKey("button_icon");
OverlayEntry _overlayEntry;
Size buttonSize;
Offset buttonPosition;
bool isMenuOpen = false;

To find the position we will use the Global key that we had created and assigned to the menu button. We can use the findRenderObject method provided by flutter to find where our menu was rendered on the screen. We create a function as shown below.

findButton() {
RenderBox renderBox = _key.currentContext.findRenderObject();
buttonSize = renderBox.size;
buttonPosition = renderBox.localToGlobal(Offset.zero);
}

Now the two variable which is in the state hold the value for our button size and the local position of the button on the screen and using this position we now have an idea where to place our drop-down menu.

Now let’s take a quick look at the overlay and the methods provided by flutter that we will be using.

Overlay entries are inserted into an Overlay using the OverlayState.insert or OverlayState.insertAll functions. To find the closest enclosing overlay for a given BuildContext, use the Overlay.of function.

An overlay entry can be in at most one overlay at a time. To remove an entry from its overlay, call the remove function on the overlay entry.

Now that we know we will require an overlay entry (we have created variable also to store it) let’s write code for it.

OverlayEntry _overlayEntryBuilder() {
return OverlayEntry(builder: (context) {
return Positioned(
top: buttonPosition.dy + buttonSize.height,
left: buttonPosition.dx,
width:buttonSize.width,
child: Material(
color: Colors.transparent,
child: //code for the drop-down menu...,
),
);
},
);
}

Here in our code, we define a function that will return an OverlayEntry. In the builder of OverlayEntry, we use a positioned widget to correctly position the drop-down menu below our menu button.

Now we define another two methods that will be used to open and close the drop-down menu when the menu button is pressed.

void openMenu() {
findButton();
_overlayEntry = _overlayEntryBuilder();
Overlay.of(context).insert(_overlayEntry);
isMenuOpen = !isMenuOpen;
}
void closeMenu() {
_overlayEntry.remove();
isMenuOpen = !isMenuOpen;
}

So the method we defined earlier to find button we will call it every-time we open the menu so that we always have the updated position and size of the menu button. We use Overlay.of(context).insert() to insert our drop-down menu in the overlay and use the OverlayEntry.remove method to remove it when the menu is closed.

In the end, we bind functions to open and close the drop-down menu with the onPressed function of a menu icon button.

onPressed: () {
if (isMenuOpen) {
closeMenu();
} else {
openMenu();
}
}

And that’s it, now we have a fully functional custom drop-down button.

The final design looks like this

For the small arrow, I have used a Path Clipper and have updated the icon button with an animated icon button.

You can find the source code for the same on my Github

--

--