Day 27: Best Practices for Implementing Pop-Up Menus in Flutter — Noted App Journey

Hemant Kumar Prajapati
6 min read2 days ago

--

Hey there, Flutter dev! 👋 Let’s talk about pop-up menus in Flutter. You know, those handy little menus that pop up when you tap on an icon or button to show extra options. They’re super useful but can sometimes get tricky to implement. No worries though, I’ve got your back!

In this guide, I’ll show you the best practices for handling pop-up menus and help you avoid some common mistakes. We’ll keep it simple, add some code, and throw in a few tips to make your UI smooth and clean. Ready? Let’s go! 🚀

| What is a Pop-Up Menu in Flutter? 🤔

A pop-up menu is a temporary menu that appears when you interact with a button or icon. It’s usually used for things like overflow menus, where you can fit extra options without taking up space on the screen.

Imagine an app with three dots (...) in the top-right corner. When you tap on it, a small menu appears with options like Edit, Delete, or Settings. That’s a pop-up menu!

Example: Basic Pop-Up Menu

Let’s look at a simple example to get started. We’ll create a button, and when the user taps on it, a pop-up menu appears with a few options.

PopupMenuButton<String>(
onSelected: (String result) {
print(result); // Handle what happens when an item is selected
},
itemBuilder: (BuildContext context) => <PopupMenuEntry<String>>[
PopupMenuItem<String>(
value: 'Edit',
child: Text('Edit ✏️'),
),
PopupMenuItem<String>(
value: 'Delete',
child: Text('Delete 🗑️'),
),
PopupMenuItem<String>(
value: 'Settings',
child: Text('Settings ⚙️'),
),
],
)

How It Works:

  • PopupMenuButton: This is the widget that triggers the pop-up menu.
  • onSelected: Called when an option is chosen.
  • itemBuilder: This builds the items for the pop-up menu (in our case, Edit, Delete, and Settings).

When the user taps an option, it’s printed in the console (print(result)), but in a real app, you’ll likely navigate somewhere or perform an action like deleting an item.

| My Way of Implementing PopupMenuButton

Let’s walk through how I integrated the PopupMenuButton into a to-do list app. Here’s the core of it:

Setting Up the List

We start by creating a ListView.builder to display our list of to-dos. Each item in the list will have a PopupMenuButton.

ListView.builder(
shrinkWrap: true,
itemCount: data.length,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
final todo = data.elementAt(index);
return Container(
margin: const EdgeInsets.all(6),
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 16),
decoration: BoxDecoration(
border: Border.all(),
color: box.any((element) =>
element.title == todo.title &&
element.category == todo.category &&
element.reminderTime == todo.reminderTime)
? TColors.appPrimaryColor
: Colors.white,
borderRadius: BorderRadius.circular(8),
boxShadow: const [
BoxShadow(
color: Colors.black,
offset: Offset(1.5, 2),
spreadRadius: 2,
blurStyle: BlurStyle.solid,
)
],
),
child: Column(
children: [
Row(
children: [
const CircleAvatar(
backgroundColor: Colors.redAccent,
radius: 8,
),
const SizedBox(width: 8),
Text(todo.category),
Spacer(),
PopupMenuHelper.buildPopupMenu(context,
onSelected: (value) async {
switch (value) {
case "complete":
await Provider.of<TodoHandlerProvider>(
context,
listen: false)
.completeTask(
todoModel: TodoModel(
title: todo.title,
category: todo.category,
isCompleted: true,
reminderTime:
todo.reminderTime,
createdAt: DateTime.now()));
break;
case "delete":
await Provider.of<TodoHandlerProvider>(
context,
listen: false)
.deleteTask(index);
break;
default:
break;
}
}, optionsList: [
if (!isCompleted) {"complete": "Complete"},
{"delete": "Delete"}
])
],
),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
todo.title,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
const Icon(Icons.flag, color: Colors.redAccent)
],
),
const Divider(),
Row(
children: [
const Icon(
Icons.calendar_month_rounded,
color: Colors.black54,
),
const SizedBox(width: 8),
Text(formatDateTimeToString(todo.createdAt)),
],
),
const SizedBox(height: 4),
Row(
children: [
const Icon(
Icons.timelapse_rounded,
color: Colors.black54,
),
const SizedBox(width: 8),
Text(formatTimeFromDateTime(todo.reminderTime)),
],
),
],
),
);
}
);

Adding the PopupMenuButton

The magic happens inside our Row widget where we add the PopupMenuButton. To keep our code clean and reusable, I created a helper class, PopupMenuHelper.

………………….

PopupMenuHelper Class

This class handles the creation of the PopupMenuButton, making it easy to manage and reuse across different parts of your app.

import 'package:flutter/material.dart';
import 'package:noted/core/app_colors.dart';

typedef PopupMenuCallback = void Function(String value);

class PopupMenuHelper {
static Widget buildPopupMenu(BuildContext context,
{required PopupMenuCallback onSelected,
required List<Map<String, String>> optionsList}) {
return PopupMenuButton<String>(
color: Colors.white,
padding: EdgeInsets.zero,
onSelected: onSelected,
itemBuilder: (BuildContext context) {
return List.generate(
optionsList.length,
(index) => PopupMenuItem<String>(
value: optionsList[index].entries.first.key,
child: Text(optionsList[index].entries.first.value),
),
);
},
child: Container(
height: 36,
width: 48,
alignment: Alignment.centerRight,
child: const Icon(Icons.more_vert),
),
);
}
}

How It Works

  • PopupMenuCallback: A typedef for our callback function to handle menu selections.
  • buildPopupMenu Method: This static method returns a PopupMenuButton widget.
  • onSelected: The callback function that handles the selected value.
  • optionsList: A list of options to display in the popup menu.
  • PopupMenuButton: The main widget that creates the popup menu.
  • itemBuilder: Generates the list of menu items.
  • child: The icon that triggers the popup menu (I used Icons.more_vert for a simple three-dot icon).

Integrating PopupMenuButton with Actions

In our ListView, we use the PopupMenuHelper.buildPopupMenu method to add the popup menu button to each todo item. When an option is selected, the corresponding action (complete or delete) is performed.

PopupMenuHelper.buildPopupMenu(context,
onSelected: (value) async {
switch (value) {
case "complete":
await Provider.of<TodoHandlerProvider>(
context,
listen: false)
.completeTask(
todoModel: TodoModel(
title: todo.title,
category: todo.category,
isCompleted: true,
reminderTime:
todo.reminderTime,
createdAt: DateTime.now()));
break;
case "delete":
await Provider.of<TodoHandlerProvider>(
context,
listen: false)
.deleteTask(index);
break;
default:
break;
}
}, optionsList: [
if (!isCompleted) {"complete": "Complete"},
{"delete": "Delete"}
])

Check this below :->

🚩 Common Mistakes to Avoid

Even though pop-up menus are easy to implement, there are a few common mistakes that developers sometimes make. Let’s make sure you avoid them!

1. ❌ Too Many Options in the Menu

Don’t overload the menu! Pop-up menus should only include quick actions. If you have more than 5 items, it’s probably better to rethink your UI.

Too many items will make your app feel cluttered and overwhelming, which is the opposite of what you want with a pop-up menu.

2. ❌ Forgetting to Handle the Selected Action

Sometimes, developers forget to implement the onSelected logic, or worse, the logic is unclear. This can confuse users if they select an option and nothing happens. Always make sure each item does what it’s supposed to!

3. ❌ Not Testing on Different Screen Sizes 📱

Pop-up menus should look good on any screen size. Test on small phones, tablets, and anything in between to ensure your menu displays properly and is usable everywhere.

| Conclusion

And that’s it! You’ve now added a PopupMenuButton to your noted app, giving users a sleek and intuitive way to manage their tasks. This approach not only keeps your UI clean but also provides a great user experience. Happy coding! 🚀

Feel free to reach out if you have any questions or need further assistance. Let’s keep building awesome Flutter apps together!

| 🚀 Join the Journey!

We’ve built an amazing todo app, “Noted App,” together, but the adventure doesn’t stop here. You can checkout the repository on GitHub and follow along day by day to complete the project with us in this open-source endeavor. 🌟💻

👉 Explore the GitHub Repository:

Dive into the code, contribute, and collaborate with other developers. Let’s build something great together.

| 🌟 Enjoyed this tutorial?

For more tips, tutorials, and insights into Flutter, be sure to follow my Medium blog! Stay connected, and let’s continue building amazing things together.

This is just Part 27: Ping me on other platforms… too….

👉 Follow me:

Happy coding! 🎉 !! Happy Flutter !!

💬 Comment Section is Open!

Share your thoughts or ask questions below.

👏 Applaud if you enjoyed this!

Your claps help others find this content.

➕ Follow for more!

Stay updated with more tips and tutorials.

🌿 Thank you for reading! If you liked this post and want to support me, you can buy me a coffee here 👇

--

--

Hemant Kumar Prajapati

▁▂▃▅▆▇ Professional Flutter Freelancer 🚀 | SDE1 at TechSaga Corporation | MVP Development for Startups 🧳 | Cross-platform App Development Expert 📱|>