Skip to content

Commit 4b39f07

Browse files
authored
Add controller argument to SubmenuButton (#125000)
## Description This adds an optional argument to the `SubmenuButton` that allows the creator to supply a `MenuController` for controlling the menu. ## Related Issues - Fixes flutter/flutter#124988 ## Tests - Added tests for new argument.
1 parent 98dfdf1 commit 4b39f07

File tree

2 files changed

+247
-171
lines changed

2 files changed

+247
-171
lines changed

packages/flutter/lib/src/material/menu_anchor.dart

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1548,6 +1548,7 @@ class SubmenuButton extends StatefulWidget {
15481548
this.onFocusChange,
15491549
this.onOpen,
15501550
this.onClose,
1551+
this.controller,
15511552
this.style,
15521553
this.menuStyle,
15531554
this.alignmentOffset,
@@ -1578,6 +1579,9 @@ class SubmenuButton extends StatefulWidget {
15781579
/// A callback that is invoked when the menu is closed.
15791580
final VoidCallback? onClose;
15801581

1582+
/// An optional [MenuController] for this submenu.
1583+
final MenuController? controller;
1584+
15811585
/// Customizes this button's appearance.
15821586
///
15831587
/// Non-null properties of this style override the corresponding properties in
@@ -1760,7 +1764,8 @@ class SubmenuButton extends StatefulWidget {
17601764
class _SubmenuButtonState extends State<SubmenuButton> {
17611765
FocusNode? _internalFocusNode;
17621766
bool _waitingToFocusMenu = false;
1763-
final MenuController _menuController = MenuController();
1767+
MenuController? _internalMenuController;
1768+
MenuController get _menuController => widget.controller ?? _internalMenuController!;
17641769
_MenuAnchorState? get _anchor => _MenuAnchorState._maybeOf(context);
17651770
FocusNode get _buttonFocusNode => widget.focusNode ?? _internalFocusNode!;
17661771
bool get _enabled => widget.menuChildren.isNotEmpty;
@@ -1777,12 +1782,15 @@ class _SubmenuButtonState extends State<SubmenuButton> {
17771782
return true;
17781783
}());
17791784
}
1785+
if (widget.controller == null) {
1786+
_internalMenuController = MenuController();
1787+
}
17801788
_buttonFocusNode.addListener(_handleFocusChange);
17811789
}
17821790

17831791
@override
17841792
void dispose() {
1785-
_internalFocusNode?.removeListener(_handleFocusChange);
1793+
_buttonFocusNode.removeListener(_handleFocusChange);
17861794
_internalFocusNode?.dispose();
17871795
_internalFocusNode = null;
17881796
super.dispose();
@@ -1810,6 +1818,9 @@ class _SubmenuButtonState extends State<SubmenuButton> {
18101818
}
18111819
_buttonFocusNode.addListener(_handleFocusChange);
18121820
}
1821+
if (widget.controller != oldWidget.controller) {
1822+
_internalMenuController = (oldWidget.controller == null) ? null : MenuController();
1823+
}
18131824
}
18141825

18151826
@override
@@ -1836,7 +1847,16 @@ class _SubmenuButtonState extends State<SubmenuButton> {
18361847
alignmentOffset: menuPaddingOffset,
18371848
clipBehavior: widget.clipBehavior,
18381849
onClose: widget.onClose,
1839-
onOpen: widget.onOpen,
1850+
onOpen: () {
1851+
if (!_waitingToFocusMenu) {
1852+
SchedulerBinding.instance.addPostFrameCallback((_) {
1853+
_menuController._anchor?._focusButton();
1854+
_waitingToFocusMenu = false;
1855+
});
1856+
_waitingToFocusMenu = true;
1857+
}
1858+
widget.onOpen?.call();
1859+
},
18401860
style: widget.menuStyle,
18411861
builder: (BuildContext context, MenuController controller, Widget? child) {
18421862
// Since we don't want to use the theme style or default style from the
@@ -1857,16 +1877,6 @@ class _SubmenuButtonState extends State<SubmenuButton> {
18571877
controller.close();
18581878
} else {
18591879
controller.open();
1860-
if (!_waitingToFocusMenu) {
1861-
// Only schedule this if it's not already scheduled.
1862-
SchedulerBinding.instance.addPostFrameCallback((Duration _) {
1863-
// This has to happen in the next frame because the menu bar is
1864-
// not focusable until the first menu is open.
1865-
controller._anchor?._focusButton();
1866-
_waitingToFocusMenu = false;
1867-
});
1868-
_waitingToFocusMenu = true;
1869-
}
18701880
}
18711881
}
18721882

0 commit comments

Comments
 (0)