4

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
  • 61
  • 1
  • 7

5 Answers5

10

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: ...),
    ];
  },
)
iDecode
  • 22,623
  • 19
  • 99
  • 186
  • 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? – Delmontee Jul 13 '21 at 13:13
  • @James Surely not something that can be explained in comments. – iDecode Jul 13 '21 at 14:38
  • @James You may also override method buildChild() from your custom class extended from PopupMenuItemState and pass null to child field of PopupMenuItem. – obezyan Aug 19 '21 at 08:55
3

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) ??
                  [],
            );
          }
Awais Abbas
  • 145
  • 9
1

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
      ],
    )
Jaimil Patel
  • 1,301
  • 6
  • 13
  • 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.. – Omi Apr 29 '20 at 12:18
  • 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 – Jaimil Patel Apr 29 '20 at 12:40
  • 2
    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 – Omi Apr 29 '20 at 13:02
1

@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)

1

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);
}
samin
  • 482
  • 5
  • 9