Learn how to implement a sleek and user-friendly popup menu in Flutter using this step-by-step tutorial. Explore the code for creating a customizable and responsive popup that enhances the user experience. Elevate your Flutter app design with this comprehensive guide. #Flutter #PopupMenu #MobileAppDevelopment

This Flutter code defines a simple app with a home screen containing a button. When the button is tapped, a popup menu is displayed with various options. Let’s break down the code step by step:

Imports:

import 'package:flutter/material.dart';

This line imports the Flutter material library, which contains widgets and classes for building material design applications.

Home Class:

class Home extends StatefulWidget {
  const Home({super.key, required this.title});

  final String title;

  @override
  State<Home> createState() => _HomeState();
}

This class represents the home screen of the app and extends StatefulWidget. It has a required title parameter, which is used in the AppBar. It overrides the createState method, creating an instance of _HomeState.

_HomeState Class:

class _HomeState extends State<Home> {
  final GlobalKey _menuKey = GlobalKey();
  // ... rest of the code
  }

This class represents the state of the home screen. It has a private member _menuKey of type GlobalKey, which will be used to identify the position of the button to display the popup menu.

showPopUp Method:

void showPopUp(BuildContext context) async {
  // ... rest of the code
}

This method is responsible for showing the popup menu. It uses the _menuKey to find the position of the button, calculates the offset, and creates an OverlayEntry to display the menu.

    final RenderBox overlay = _menuKey.currentContext!.findRenderObject() as RenderBox;
    final Offset offset = overlay.localToGlobal(Offset.zero);
    final double screenWidth = MediaQuery.of(context).size.width;
    OverlayEntry? overlayEntry;
    overlayEntry = OverlayEntry(
      builder: (context) {
        // ... rest of the code
        return Positioned(
          // ... positioning and styling code
          left: (screenWidth - 200) / 2,
          top: offset.dy + overlay.size.height,
          width: 200,
          child: Material(
            // ... material design properties
            clipBehavior: Clip.antiAlias,
            elevation: 3,
            color: Colors.white,
            shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
            child: Column(
              children: [
               // ... list of ListTile items representing menu options
              ],
            ),
          ),
        );
      },
    );
    Overlay.of(context).insert(overlayEntry);

This code defines the structure of the popup menu using the Overlay widget. It contains a Material widget with a Column of ListTile items, each representing a different option in the menu.

build Method:

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      backgroundColor: Theme.of(context).colorScheme.inversePrimary,
      title: Text(widget.title),
    ),
    body: Center(
      child: InkWell(
        key: _menuKey,
        onTap: () {
          showPopUp(context);
        },
        child: const Text(
          'Open Pop Up Menu',
        ),
      ),
    ),
  );
}

This method builds the actual UI for the home screen. It returns a Scaffold with an AppBar and a Center widget containing an InkWell. Tapping on the InkWell triggers the showPopUp method, displaying the popup menu.

Demo / Screenshot

Pop Menu Demo

Full Code

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const Home(title: 'Flutter Custom Pop Up Menu'),
    );
  }
}

class Home extends StatefulWidget {
  const Home({super.key, required this.title});

  final String title;

  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {
  final GlobalKey _menuKey = GlobalKey();

  void showPopUp(BuildContext context) async {
    final RenderBox overlay = _menuKey.currentContext!.findRenderObject() as RenderBox;
    final Offset offset = overlay.localToGlobal(Offset.zero);
    final double screenWidth = MediaQuery.of(context).size.width;
    OverlayEntry? overlayEntry;
    overlayEntry = OverlayEntry(
      builder: (context) {
        // ... rest of the code
        return Positioned(
          // ... positioning and styling code
          left: (screenWidth - 200) / 2,
          top: offset.dy + overlay.size.height,
          width: 200,
          child: Material(
            // ... material design properties
            clipBehavior: Clip.antiAlias,
            elevation: 3,
            color: Colors.white,
            shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
            child: Column(
              children: [
                // ... list of ListTile items representing menu options
                ListTile(
                  onTap: () {
                    overlayEntry?.remove();
                  },
                  leading: const Icon(
                    Icons.account_circle_outlined,
                    size: 22,
                    color: Color(0xff9994b0),
                  ),
                  title: const Text(
                    'Profile Details',
                    style: TextStyle(
                      fontSize: 14,
                      color: Colors.black,
                      fontWeight: FontWeight.w600,
                    ),
                  ),
                ),
                ListTile(
                    onTap: () {
                      overlayEntry?.remove();
                    },
                    leading: const Icon(
                      Icons.currency_rupee_outlined,
                      size: 22,
                      color: Color(0xff9994b0),
                    ),
                    title: const Text(
                      'Plans & Billing',
                      style: TextStyle(
                        fontSize: 14,
                        color: Colors.black,
                        fontWeight: FontWeight.w600,
                      ),
                    )),
                ListTile(
                  onTap: () {
                    overlayEntry?.remove();
                  },
                  leading: const Icon(
                    Icons.integration_instructions_outlined,
                    size: 22,
                    color: Color(0xff9994b0),
                  ),
                  title: const Text('Integrations',
                      style: TextStyle(
                        fontSize: 14,
                        color: Colors.black,
                        fontWeight: FontWeight.w600,
                      )),
                ),
                ListTile(
                  onTap: () {
                    overlayEntry?.remove();
                  },
                  leading: const Icon(
                    Icons.help_outline,
                    size: 22,
                    color: Color(0xff9994b0),
                  ),
                  title: const Text('Help Center',
                      style: TextStyle(
                        fontSize: 14,
                        color: Colors.black,
                        fontWeight: FontWeight.w600,
                      )),
                ),
                ListTile(
                  onTap: () {
                    overlayEntry?.remove();
                  },
                  leading: const Icon(
                    Icons.credit_card,
                    size: 22,
                    color: Color(0xff9994b0),
                  ),
                  title: const Text('Subscription',
                      style: TextStyle(
                        fontSize: 14,
                        color: Colors.black,
                        fontWeight: FontWeight.w600,
                      )),
                ),
                ListTile(
                  onTap: () {
                    overlayEntry?.remove();
                  },
                  leading: const Icon(
                    Icons.logout_outlined,
                    size: 22,
                    color: Color(0xff9994b0),
                  ),
                  title: const Text('Log Out',
                      style: TextStyle(
                        fontSize: 14,
                        color: Colors.black,
                        fontWeight: FontWeight.w600,
                      )),
                )
              ],
            ),
          ),
        );
      },
    );
    Overlay.of(context).insert(overlayEntry);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: InkWell(
          key: _menuKey,
          onTap: () {
            showPopUp(context);
          },
          child: const Text(
            'Open Pop Up Menu',
          ),
        ),
      ),
    );
  }
}

Write A Comment

Pin It
Top Most Used Animation Widgets You Need to Know in 2024 Top 10+ Free Websites for Hosting for Beginners Developers Flutter AbsorbPointer class Use case in Depth 2023