How not to dismiss a PopUpMenuButton after selecting an item?

1,573

Solution 1

Create a custom class, say PopupItem, which extends PopupMenuItem and override PopupMenuItemState.handleTap method.

class PopupItem extends PopupMenuItem {
  const PopupItem({
    required Widget child,
    Key? key,
  }) : super(key: key, child: child);

  @override
  _PopupItemState createState() => _PopupItemState();
}

class _PopupItemState extends PopupMenuItemState {
  @override
  void handleTap() {}
}

You can now use it like this:

PopupMenuButton(
  itemBuilder: (_) {
    return [
      PopupItem(child: ...),
    ];
  },
)

Solution 2

So I had a requirement where I had to

create a form field with a drop-down menu with checkable items

So I created a popup menu with PopupMenuItem but then I had 3 problems

  1. When an item was selected popup was getting dismissed
  2. Clicking on the checkbox was not updating the checkbox state
  3. Clicking on the text was not updating the check box

So I solved all these issues like this, this may help you guys

  1. Set enabled = false in PopupMenuItem and Wrapped the child with a gesture listener for click listeners
  2. Used StatefulBuilder to update the state
  3. Solution 1 solved this problem too

Here is the code ->

   onTapDown: (details) async {
            state.didChange(
              await showMenu(
                    context: context,
                    position: RelativeRect.fromLTRB(
                      details.globalPosition.dx,
                      details.globalPosition.dy,
                      0,
                      0,
                    ),
                    items: itemList.keys
                        .map(
                          (e) => PopupMenuItem(
                            enabled: false,
                            child: StatefulBuilder(
                              builder: (BuildContext context,
                                  StateSetter setState) {
                                return GestureDetector(
                                  onTap: () {
                                    setState(() {
                                      itemList[e] = !itemList[e]!;
                                    });
                                  },
                                  child: Row(
                                    children: [
                                      Expanded(child: Text(e)),
                                      Checkbox(
                                        value: itemList[e],
                                        onChanged: (i) {
                                          setState(() {
                                            itemList[e] = i!;
                                          });
                                        },
                                      ),
                                    ],
                                  ),
                                );
                              },
                            ),
                          ),
                        )
                        .toList(),
                    elevation: 8.0,
                  ).then((value) => null) ??
                  [],
            );
          }

Solution 3

@Omi,

I had faced similar situation... wanted a Popup but didn't want it to be dismissed when I select a PopupMenuItem.

I had implemented this :

enabled → bool Whether the user is permitted to select this item. [...]

I have set enabled to false for the menu item (In my case it was a card having my custom UI)

Solution 4

You can use CheckedPopupMenuItem like this.. as mentioned at Official Documentation

PopupMenuButton<Commands>(
      onSelected: (Commands result) {
        switch (result) {
          case Commands.heroAndScholar:
            setState(() { _heroAndScholar = !_heroAndScholar; });
            break;
          case Commands.hurricaneCame:
            // ...handle hurricane option
            break;
          // ...other items handled here
        }
      },
      itemBuilder: (BuildContext context) => <PopupMenuEntry<Commands>>[
        CheckedPopupMenuItem<Commands>(
          checked: _heroAndScholar,
          value: Commands.heroAndScholar,
          child: const Text('Hero and scholar'),
        ),
        const PopupMenuDivider(),
        const PopupMenuItem<Commands>(
          value: Commands.hurricaneCame,
          child: ListTile(leading: Icon(null), title: Text('Bring hurricane')),
        ),
        // ...other items listed here
      ],
    )

Solution 5

You have to modifythe package popupmenubutton. Whenever something is selected in the menu, the menu popped out. So you have to just comment out the Navigator.pop() in the main file of this widget. comment out the Navigator.pop<T>(context, widget.value); in the the main file.

/// The handler for when the user selects the menu item.
///
/// Used by the [InkWell] inserted by the [build] method.
///
/// By default, uses [Navigator.pop] to return the [PopupMenuItem.value] from
/// the menu route.
@protected
void handleTap() {
widget.onTap?.call();

// Navigator.pop<T>(context, widget.value);
}
Share:
1,573
Omi
Author by

Omi

Updated on December 01, 2022

Comments

  • Omi
    Omi over 1 year

    I am using flutter PopUpMenuButton. All i want is when i select any item on the menu, the popup should not be dismissed, rather let me select multiple values from the popup.The documentation says that you can override the handleTap property, but it is unclear for me how to do that? This is documented

     ///The [handleTap] method can be overridden to adjust exactly what happens when
    /// the item is tapped. By default, it uses [Navigator.pop] to return the
    /// [PopupMenuItem.value] from the menu route.
    
        void handleTap() {
        Navigator.pop<T>(context, widget.value);
      }
    
  • Omi
    Omi about 4 years
    this surely works, but i wanted to add a custom radio button with animation, i don't this CheckedPopUpMenu button will allow me to do this. Btw thanks for answering..
  • Jaimil Patel
    Jaimil Patel about 4 years
    Please upvote my answer if it maches according to your questions. i know that you want to implement Radio button instead of CheckedPopupMenu button but for other user it will be usefull
  • Omi
    Omi about 4 years
    i just tried CheckedPopUpmenu button, it doesnt work either, i don't know why, it just gets ticked and the menu dismissed, i am not able to select multiple value
  • Delmontee
    Delmontee almost 3 years
    How can you use this in a stateful widget, to update the display? For example, a menu with a list of checkboxes. User clicks a checkbox, the value toggles from on/off and it is updated on screen?
  • iDecode
    iDecode almost 3 years
    @James Surely not something that can be explained in comments.
  • obezyan
    obezyan over 2 years
    @James You may also override method buildChild() from your custom class extended from PopupMenuItemState and pass null to child field of PopupMenuItem.
  • Rahul Singh
    Rahul Singh over 2 years
    It works perfectly. But I am facing an issue Text displays in grey color because widget is disabled (I have Displayed Text in pop up menu with Blue color). Is there a way to override disabled behaviour in pop up menu item
  • Awais Abbas
    Awais Abbas over 2 years
    @RahulSingh did you try to add text style?
  • Rahul Singh
    Rahul Singh over 2 years
    After you pointed out that I did and It works. Thanks For the help