@@ -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 {
17601764class _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