Closed Caffeinix closed 1 month ago
Thanks for filing the issue. Reproduced this on the latest stable and master channels.
Also, I see there is a workaround for this by using IgnorePointer
for the underlying widget and using a flag to trigger it by MenuAnchor
's onOpen
and onClose
callbacks.
Maybe this will also be resolved once https://github.com/flutter/flutter/issues/124830 is completed, you may follow it as well.
TapRegion
was actually added for menus (to replace FocusTrap
), partly because it was necessary to be able to capture the previously focused node and restore it when the menu is dismissed, and a route masks that by changing the focus before notifying of the route change. Before that, we used to use a modal route, but it caused a lot of other problems. For instance, context menus on mobile shouldn't eat the key event because it makes it hard to implement a "copy" or "clear" button next to a text field that operates as expected.
It's going to be hard to stop the propagation of the pointer event that a TapRegion
sees because the TapRegion
doesn't (by design) participate in the gesture arena, so there's no way to indicate that the event has been handled.
I'll look and see if there's a way to stop propagation of the event, and look into adding one if there isn't a mechanism. In any case, it'll probably need to be a configuration setting as to whether or not it eats the click, since there are cases where that isn't wanted.
This issue is assigned to @gspencergoog but has had no recent status updates. Please consider unassigning this issue if it is not going to be addressed in the near future. This allows people to have a clearer picture of what work is actually planned. Thanks!
This issue was assigned to @gspencergoog but has had no status updates in a long time. To remove any ambiguity about whether the issue is being worked on, the assignee was removed.
Closing because, since https://github.com/flutter/flutter/pull/136305, the property MenuAnchor.consumeOutsideTap
is available and can be set to true
to get the desired behavior.
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v
and a minimal reproduction of the issue.
Steps to reproduce
MenuAnchor
to show a menu.Expected results
Tapping or clicking outside of a menu to close it should not activate whatever element is under the mouse or finger. This behavior is consistent between native menus on all operating systems and the implementation of
PopupMenuButton
andshowMenu
. In all these cases, the menu acts as a modal overlay for the purposes of these events.Actual results
Tapping or clicking outside of a menu to close it does succeed in closing the menu, but it also triggers any tap event handlers on the element under the mouse or finger. This is contrary to convention and also general UX principles (a single tap should not trigger two different unrelated actions on two independent controls).
The bad behavior appears to be a consequence of no longer using a modal route for menus, and it seems to me that
anchorTapClosesMenu
may be a band-aid for other related consequences of that decision. While making the menu fully modal would make cascading menus very difficult (which I presume is why it wasn't done that way in the first place), some modal-ish behavior is likely necessary to avoid bugs like these.Code sample
Here's a modified version of the `MenuAnchor` example code that shows a SnackBar whenever the background container receives a tap event. Open the menu and then click outside of it to close it, and you will see the SnackBar appear as the menu closes.
```dart import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; /// Flutter code sample for [MenuAnchor]. void main() => runApp(const MenuApp()); /// An enhanced enum to define the available menus and their shortcuts. /// /// Using an enum for menu definition is not required, but this illustrates how /// they could be used for simple menu systems. enum MenuEntry { about('About'), showMessage( 'Show Message', SingleActivator(LogicalKeyboardKey.keyS, control: true)), hideMessage( 'Hide Message', SingleActivator(LogicalKeyboardKey.keyS, control: true)), colorMenu('Color Menu'), colorRed('Red Background', SingleActivator(LogicalKeyboardKey.keyR, control: true)), colorGreen('Green Background', SingleActivator(LogicalKeyboardKey.keyG, control: true)), colorBlue('Blue Background', SingleActivator(LogicalKeyboardKey.keyB, control: true)); const MenuEntry(this.label, [this.shortcut]); final String label; final MenuSerializableShortcut? shortcut; } class MyCascadingMenu extends StatefulWidget { const MyCascadingMenu({super.key, required this.message}); final String message; @override StateScreenshots or Video
Screenshots / Video demonstration
[cast.webm](https://github.com/flutter/flutter/assets/1880449/c174eca8-7004-45b6-9b3d-a68de2b4e628)