Settings Button in Flutter

Settings button in Flutter is nothing but the pop up menu buttons. In other words, these settings buttons in AppBar always act as menu buttons. It looks like three dots, and pops up when user clicks on it.

From the design point of view, it looks very simple, but it’s extremely useful.

Why?

Because, we might navigate to other pages bu clicking each button.

For instance, consider the following screenshot.

Home page showing settings button in flutter
Home page showing settings button in flutter

We’ve clicked the three dots, and three pages have popped up.

Now, if we click any page, it will take us to that page. Most importantly, we can create custom pop up menu buttons for each page to create a complex application structure.

Let’s see the home page code first. Meanwhile, we’ll explain how the PopupMenuButton widget works.

import 'package:flutter/material.dart';
import '../../model/painter/amber_painter.dart';

import '/model/settings.dart';

import 'settings.dart';
import 'signup.dart';
import 'subscribe.dart';

class SettingsHomePage extends StatefulWidget {
  const SettingsHomePage({Key? key}) : super(key: key);

  @override
  State<SettingsHomePage> createState() => _SettingsHomePageState();
}

class _SettingsHomePageState extends State<SettingsHomePage> {
  static const String title = 'Settings Buttons';

  @override
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: customAppBar(title),
      body: CustomPaint(
        painter: AmberPainter(),
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: const <Widget>[
              Text(
                'Settings Home Page',
                style: TextStyle(
                  fontSize: 40,
                  fontWeight: FontWeight.bold,
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }

  void choiceAction(String choice) {
    if (choice == Settings.settings) {
    } else if (choice == Settings.signUp) {
    } else if (choice == Settings.subscribe) {}
  }

  AppBar customAppBar(String title) {
    return AppBar(
      centerTitle: true,
      //backgroundColor: Colors.grey[400],
      flexibleSpace: Container(
        decoration: const BoxDecoration(
          gradient: LinearGradient(
            colors: [
              Colors.amber,
              Colors.grey,
            ],
            begin: Alignment.topRight,
            end: Alignment.bottomRight,
          ),
        ),
      ),
      //elevation: 20,
      titleSpacing: 80,
      leading: const Icon(Icons.menu),
      title: Text(
        title,
        textAlign: TextAlign.left,
      ),
      actions: [
        buildIcons(
          const Icon(Icons.search),
        ),
        buildIcons(
          const Icon(
            Icons.settings,
          ),
        ),
        PopupMenuButton<String>(
          onSelected: choiceAction,
          itemBuilder: (BuildContext context) {
            return Settings.choices.map(
              (String choice) {
                return PopupMenuItem<String>(
                  value: choice,
                  child: GestureDetector(
                    child: Text(choice),
                    onTap: () {
                      choice == Settings.settings
                          ? Navigator.push(
                              context,
                              MaterialPageRoute(
                                  builder: (context) => const SettingsPage()))
                          : choice == Settings.signUp
                              ? Navigator.push(
                                  context,
                                  MaterialPageRoute(
                                      builder: (context) => const SignUpPage()))
                              : choice == Settings.subscribe
                                  ? Navigator.push(
                                      context,
                                      MaterialPageRoute(
                                          builder: (context) =>
                                              const SubscribePage()))
                                  : const SettingsHomePage();
                    },
                  ),
                );
              },
            ).toList();
          },
        ),
      ],
    );
  }

  IconButton buildIcons(Icon icon) {
    return IconButton(
      onPressed: () {},
      icon: icon,
    );
  }
}

Although the code looks a little longer, yet it’s quite simple in nature.

That is to say, if we follow the bold sections, we’ll understand the flow of logic.

However, we have a model data class that also takes part when we choose one particular settings.

class Settings {
  static const String subscribe = 'Subscribe';
  static const String settings = 'Settings';
  static const String signUp = 'Sign Up';

  static const List<String> choices = <String>[
    subscribe,
    settings,
    signUp,
  ];
}

The above code is the list of menus that we display on our AppBar. After that, we call onSelected parameter that returns a callback.

As a result, we’ve already defined that in our home page.

 void choiceAction(String choice) {
    if (choice == Settings.settings) {
    } else if (choice == Settings.signUp) {
    } else if (choice == Settings.subscribe) {}
  }

Subsequently, we use this void method inside our pop up menu button.

PopupMenuButton<String>(
          onSelected: choiceAction,
          itemBuilder: (BuildContext context) {
....

During the item building process, the callback plays an important role.

The value passed to onSelected is the value of the selected menu item.

That’s why, we are able to navigate to the value or page passed to the onSelected callback.

Besides, child or icon, PopupMenuButton has a parameter “itemBuilder”. With the help of this parameter, we can build a list of items.

As a result, we return a PopupMenuItem where we map the settings model class to list.

What is pop up menu item?

To create a button that shows a pop up menu, we’ve used PopupMenuButton.

Similarly, each time we can access an item in a material design menu.

Usually the the child of a PopupMenuItem is a Text widget.

In our case the same thing happens, although we have wrapped the Text widget with a Gesture detector widget.

PopupMenuButton<String>(
          onSelected: choiceAction,
          itemBuilder: (BuildContext context) {
            return Settings.choices.map(
              (String choice) {
                return PopupMenuItem<String>(
                  value: choice,
                  child: GestureDetector(
                    child: Text(choice),
                    onTap: () {
                      choice == Settings.settings
...

Why the gesture detector?

Because we wanted to use the onTap callback. Moreover, we can check the choice of settings and accordingly navigate to that page.

If we click subscribe, in the pop up menu items, we go to that page.

Subscribe page with custom paint
Subscribe page with custom paint

If we click settings, we go to that page.

Settings page with custom paint
Settings page with custom paint

Or, if we click the sign up page, we can navigate to the sign up page.

Sign up page with custom paint
Sign up page with custom paint

As we’ve used separate custom paint for each page, it looks different. In addition, to avoid complexity. we didn’t use separate pop up menu button for each page.

But we could have done that.

For full code snippet, please visit the respective GitHub repository.

What Next?

Books at Leanpub

Books in Apress

My books at Amazon

GitHub repository

Technical blog

Twitter

Comments

Leave a Reply