Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
b5eb1d7
Add fix to menu anchor
davidhicks980 Feb 13, 2026
41e7787
Add regression text
davidhicks980 Feb 13, 2026
8a7f896
Remove unnecessary closeChildren calls.
davidhicks980 Feb 13, 2026
d209ca4
Add async test and an additional comment reminding users to cancel th…
davidhicks980 Feb 14, 2026
33a0c8e
Merge branch 'master' into raw_menu_anchor_close_order
davidhicks980 Feb 14, 2026
40bf127
Implement Tong suggestions
davidhicks980 Feb 26, 2026
47ba4db
Flip request close sequence
davidhicks980 Feb 26, 2026
6709c9e
short circuit close requests if menu is already closed.
davidhicks980 Feb 26, 2026
3221cf2
Merge branch 'master' into raw_menu_anchor_close_order
davidhicks980 Feb 26, 2026
c34e489
parent => sibling
davidhicks980 Feb 26, 2026
8781e8c
parent => sibling
davidhicks980 Feb 26, 2026
f7037be
Elaborate on disabling interactivity
davidhicks980 Feb 26, 2026
abf169b
Clarify comments
davidhicks980 Feb 26, 2026
8ce071c
remove comma
davidhicks980 Feb 26, 2026
97c9c47
Merge branch 'master' into raw_menu_anchor_close_order
davidhicks980 Mar 2, 2026
cc314fe
Merge branch 'master' into raw_menu_anchor_close_order
davidhicks980 Apr 2, 2026
96d2393
Tong suggestions
davidhicks980 Apr 2, 2026
0d7b8f6
Tong changes slightly modified
davidhicks980 Apr 2, 2026
15716d9
Merge branch 'master' into raw_menu_anchor_close_order
davidhicks980 Apr 6, 2026
9e088c6
Merge branch 'master' into raw_menu_anchor_close_order
dkwingsmt Apr 6, 2026
193ed58
Merge branch 'master' into raw_menu_anchor_close_order
dkwingsmt Apr 7, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,6 @@ class MenuState extends State<Menu> with SingleTickerProviderStateMixin {
return;
}

// Animate the menu's children out of view.
menuController.closeChildren();

// Animate the menu out of view.
animationController.reverse().whenComplete(hideOverlay);
}
Expand Down
1 change: 0 additions & 1 deletion packages/flutter/lib/src/material/menu_anchor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -656,7 +656,6 @@ class _MenuAnchorState extends State<MenuAnchor> with SingleTickerProviderStateM
return;
}

_menuController.closeChildren();
_animationController.reverse().whenComplete(hideOverlay);
}

Expand Down
74 changes: 57 additions & 17 deletions packages/flutter/lib/src/widgets/raw_menu_anchor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -310,10 +310,23 @@ class RawMenuAnchor extends StatefulWidget {

/// Called when a request is made to close the menu.
///
/// This callback is triggered every time [MenuController.close] is called,
/// regardless of whether the overlay is already hidden. As a result, this
/// callback can be used to add a delay or a closing animation before the menu
/// is hidden.
/// This callback can be used to add a delay or a closing animation before the
/// menu is hidden.
///
/// This callback is triggered every time [MenuController.close] is called
/// while this menu is open.
///
/// This callback is also triggered when a sibling [RawMenuAnchor] is opened
/// while this menu is open. In this case, the callback can be used to add a
/// delay or a closing animation while the sibling menu opens. When
/// implementing this behavior, consider disabling interactions so that the
/// closing menu does not interfere with the opening sibling menu. Also
/// consider disabling semantics, focus, and hit testing for the closing menu
/// for the duration of the closing animation.
///
/// Pending timers or animations started in a previous call to
/// [onCloseRequested] should be canceled when this callback is triggered to
/// prevent them from closing the menu at an unintended time.
///
/// If the menu is not closed, this callback will also be called when the root
/// menu anchor is scrolled and when the screen is resized.
Expand Down Expand Up @@ -600,22 +613,40 @@ mixin _RawMenuAnchorBaseMixin<T extends StatefulWidget> on State<T> {
@protected
void handleCloseRequest();

/// Request that the submenus of this menu be closed.
/// Close the open submenus of this menu.
///
/// By default, this method will call [handleCloseRequest] on each child of this
/// menu, which will trigger the closing sequence of each child.
/// This method will call [close] on each child of this menu, which will
/// immediately close the child.
///
/// If `inDispose` is true, this method was triggered by the widget being
/// unmounted.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a see also to reference closeChildrenWithRequest and vice versa

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

///
/// See also:
/// * [requestChildrenClose], which triggers the closing sequence of each
/// child by calling [handleCloseRequest] on each child.
@protected
void closeChildren({bool inDispose = false}) {
assert(_debugMenuInfo('Closing children of $this${inDispose ? ' (dispose)' : ''}'));
for (final child in List<_RawMenuAnchorBaseMixin>.of(_anchorChildren)) {
if (inDispose) {
child.close(inDispose: inDispose);
} else {
child.handleCloseRequest();
}
final children = List<_RawMenuAnchorBaseMixin>.of(_anchorChildren);
for (final child in children) {
child.close(inDispose: inDispose);
}
}

/// Request that the open submenus of this menu be closed.
///
/// This method will call [handleCloseRequest] on each child of this menu,
/// which will trigger the closing sequence of each child.
///
/// See also:
/// * [closeChildren], which immediately closes each child without triggering
/// the closing sequence.
@protected
void requestChildrenClose() {
assert(_debugMenuInfo('Calling handleCloseRequest for children of $this'));
final children = List<_RawMenuAnchorBaseMixin>.of(_anchorChildren);
for (final child in children) {
child.handleCloseRequest();
}
}

Expand All @@ -626,7 +657,7 @@ mixin _RawMenuAnchorBaseMixin<T extends StatefulWidget> on State<T> {
void handleOutsideTap(PointerDownEvent pointerDownEvent) {
assert(_debugMenuInfo('Tapped Outside $menuController'));
if (isOpen) {
closeChildren();
requestChildrenClose();
}
}

Expand Down Expand Up @@ -708,7 +739,7 @@ class _RawMenuAnchorState extends State<RawMenuAnchor> with _RawMenuAnchorBaseMi
assert(_debugMenuInfo('Opening $this at ${position ?? Offset.zero}'));

// Close all siblings.
_parent?.closeChildren();
_parent?.requestChildrenClose();
assert(!_overlayController.isShowing);
_menuPosition = position;
_parent?._childChangedOpenState();
Expand All @@ -731,7 +762,9 @@ class _RawMenuAnchorState extends State<RawMenuAnchor> with _RawMenuAnchorBaseMi
return;
}

// Parents will close after children do.
closeChildren(inDispose: inDispose);

// Don't hide if we're in the middle of a build.
if (SchedulerBinding.instance.schedulerPhase != SchedulerPhase.persistentCallbacks) {
_overlayController.hide();
Expand Down Expand Up @@ -764,6 +797,10 @@ class _RawMenuAnchorState extends State<RawMenuAnchor> with _RawMenuAnchorBaseMi

@override
void handleCloseRequest() {
if (!isOpen) {
return;
}

// Changes in MediaQuery.sizeOf(context) cause RawMenuAnchor to close during
// didChangeDependencies. When this happens, calling setState during the
// closing sequence (handleCloseRequest -> onCloseRequested -> hideOverlay)
Expand All @@ -779,6 +816,9 @@ class _RawMenuAnchorState extends State<RawMenuAnchor> with _RawMenuAnchorBaseMi
}
}, debugLabel: 'RawMenuAnchor.handleCloseRequest');
}

// Parents will request close before children do.
requestChildrenClose();
}

Widget _buildOverlay(BuildContext context, OverlayChildLayoutInfo layoutInfo) {
Expand Down Expand Up @@ -939,7 +979,7 @@ class _RawMenuAnchorGroupState extends State<RawMenuAnchorGroup>
@override
void handleCloseRequest() {
assert(_debugMenuInfo('Requesting close $this'));
close();
requestChildrenClose();
}

@override
Expand Down Expand Up @@ -1018,7 +1058,7 @@ class MenuController {
/// without closing the menu itself.
void closeChildren() {
assert(_anchor != null);
_anchor!.closeChildren();
_anchor!.requestChildrenClose();
}

// ignore: use_setters_to_change_properties
Expand Down
Loading