MenuAnchor doesn’t close when clicking on buttons or outside in Flutter (only works on blank area, using deprecated anchorTapClo

I am building a menu system in Flutter, and I have encountered an issue where my menu does not close wh

I am building a menu system in Flutter, and I have encountered an issue where my menu does not close when I click on a button inside the UI. However, if I set the anchorTapClosesMenu property to true (deprecated feature), the menu closes correctly when clicking on a blank area

Initially, I was using PopupMenuButton, but it didn’t work well with submenus and it had some ugly padding. The documentation suggested migrating to MenuAnchor, so I switched to that approach. I also saw an example with a submenu in the MenuAnchor documentation, which convinced me that it would be a good fit for my use case.

What I Tried:

I am using a MenuController with MenuAnchor to control the menu state. I want to close the menu when clicking anywhere outside, but I am unable to make it close when clicking on UI buttons. I tried using a GestureDetector with the onTapDown method to handle tap events. However, this prevents the UI behind the menu from receiving tap events, which interferes with normal behavior. I considered using a flag to ignore events but still allow for the UI to behave correctly, but HitTestBehavior.translucent or IgnorePointer don't work as expected.

Additional Context:

I'm trying to implement this feature in Flutter Web to mimic a standard context menu with sub-menus.

I tried debugging the menu package itself for a long time, trying to understand why the menu behaves unexpectedly, and found that the menu might be immediately reopening whenever I click on the UI. It seems like the package detects clicking on the UI as being inside the tap region, which prevents the menu from closing when clicking on UI elements.

Also, I didn't really see how to connect the menu area and the widgets in my code As a result, I tried by using Riverpod, where the menu is wrapping my entire app UI to use the full UI as the anchor and allowing me to use riverpod to call the controller's method

Code Snippets:

class MenuState {
  final List<Widget> menuItems;
  MenuState({required this.menuItems});
}

class MenuStateNotifier extends StateNotifier<MenuState> {
  final MenuController menuController;
  MenuStateNotifier(this.menuController) : super(MenuState(menuItems: []));

  void openWebMenu(Offset position, List<Widget> items) {
    state = MenuState(menuItems: items);
    if (menuController.isOpen) {
      menuController.close();
    } else {
      menuController.open(position: position);
    }
  }
}

final menuStateProvider = StateNotifierProvider<MenuStateNotifier, MenuState>((ref) {
  return MenuStateNotifier(MenuController());
});

What's written in the menuAnchor documentation is to use a GestureDetector to close the menu but that prevents any event from going through

void _handleTapDown(TapDownDetails details) {
  if (_menuController.isOpen) {
    _menuController.close();
    return;
  }
  // Additional logic for opening the menu
  switch (defaultTargetPlatform) {
    case TargetPlatform.iOS:
    case TargetPlatform.macOS:
      if (HardwareKeyboard.instance.logicalKeysPressed.contains(LogicalKeyboardKey.controlLeft) ||
          HardwareKeyboard.instance.logicalKeysPressed.contains(LogicalKeyboardKey.controlRight)) {
        _menuController.open(position: details.localPosition);
      }
      break;
  }
}

Riverpod Menu Integration:

class RiverPodMenu extends ConsumerStatefulWidget {
  final Widget child;
  const RiverPodMenu({super.key, required this.child});

  @override
  ConsumerState<ConsumerStatefulWidget> createState() => _RiverPodMenuState();
}

class _RiverPodMenuState extends ConsumerState<RiverPodMenu> {
  @override
  Widget build(BuildContext context) {
    final menuNotifier = ref.watch(menuStateProvider.notifier);
    final menuState = ref.watch(menuStateProvider);

    return MenuAnchor(
      anchorTapClosesMenu: true,  // Deprecated flag but works for outside clicks
      controller: menuNotifier.menuController,
      menuChildren: menuState.menuItems,
      child: widget.child,
    );
  }
}

Menu state:

The menu currently closes only when clicking on a blank area, relying on a deprecated feature. Using a GestureDetector to intercept tap events prevents the UI behind the menu from receiving interactions.

Questions:

  • Why does the menu close when clicking outside but not when clicking on UI buttons?
  • Can parent and child GestureDetector widgets trigger simultaneously?
  • How can I close the menu when interacting with UI elements while still allowing them to function?
  • Is there a better approach to managing and communicating with this type of menu across the app, especially when the widget that triggers the menu is deeply nested?

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744720745a4589894.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信