Unverified Commit 9a344c26 authored by Henry Riehl's avatar Henry Riehl Committed by GitHub

Add option to keep ```MenuAnchor``` open after ```MenuItem``` tap (#123723)

Add option to keep ```MenuAnchor``` open after ```MenuItem``` tap
parent 63e30480
...@@ -810,6 +810,7 @@ class MenuItemButton extends StatefulWidget { ...@@ -810,6 +810,7 @@ class MenuItemButton extends StatefulWidget {
this.clipBehavior = Clip.none, this.clipBehavior = Clip.none,
this.leadingIcon, this.leadingIcon,
this.trailingIcon, this.trailingIcon,
this.closeOnActivate = true,
required this.child, required this.child,
}); });
...@@ -871,6 +872,14 @@ class MenuItemButton extends StatefulWidget { ...@@ -871,6 +872,14 @@ class MenuItemButton extends StatefulWidget {
/// An optional icon to display after the [child] label. /// An optional icon to display after the [child] label.
final Widget? trailingIcon; final Widget? trailingIcon;
/// {@template flutter.material.menu_anchor.closeOnActivate}
/// Determines if the menu will be closed when a [MenuItemButton]
/// is pressed.
///
/// Defaults to true.
/// {@endtemplate}
final bool closeOnActivate;
/// The widget displayed in the center of this button. /// The widget displayed in the center of this button.
/// ///
/// Typically this is the button's label, using a [Text] widget. /// Typically this is the button's label, using a [Text] widget.
...@@ -1089,7 +1098,9 @@ class _MenuItemButtonState extends State<MenuItemButton> { ...@@ -1089,7 +1098,9 @@ class _MenuItemButtonState extends State<MenuItemButton> {
void _handleSelect() { void _handleSelect() {
assert(_debugMenuInfo('Selected ${widget.child} menu')); assert(_debugMenuInfo('Selected ${widget.child} menu'));
widget.onPressed?.call(); widget.onPressed?.call();
_MenuAnchorState._maybeOf(context)?._root._close(); if (widget.closeOnActivate) {
_MenuAnchorState._maybeOf(context)?._root._close();
}
} }
void _createInternalFocusNodeIfNeeded() { void _createInternalFocusNodeIfNeeded() {
...@@ -1140,6 +1151,7 @@ class CheckboxMenuButton extends StatelessWidget { ...@@ -1140,6 +1151,7 @@ class CheckboxMenuButton extends StatelessWidget {
this.statesController, this.statesController,
this.clipBehavior = Clip.none, this.clipBehavior = Clip.none,
this.trailingIcon, this.trailingIcon,
this.closeOnActivate = true,
required this.child, required this.child,
}); });
...@@ -1242,6 +1254,9 @@ class CheckboxMenuButton extends StatelessWidget { ...@@ -1242,6 +1254,9 @@ class CheckboxMenuButton extends StatelessWidget {
/// An optional icon to display after the [child] label. /// An optional icon to display after the [child] label.
final Widget? trailingIcon; final Widget? trailingIcon;
/// {@macro flutter.material.menu_anchor.closeOnActivate}
final bool closeOnActivate;
/// The widget displayed in the center of this button. /// The widget displayed in the center of this button.
/// ///
/// Typically this is the button's label, using a [Text] widget. /// Typically this is the button's label, using a [Text] widget.
...@@ -1292,6 +1307,7 @@ class CheckboxMenuButton extends StatelessWidget { ...@@ -1292,6 +1307,7 @@ class CheckboxMenuButton extends StatelessWidget {
), ),
clipBehavior: clipBehavior, clipBehavior: clipBehavior,
trailingIcon: trailingIcon, trailingIcon: trailingIcon,
closeOnActivate: closeOnActivate,
child: child, child: child,
); );
} }
...@@ -1332,6 +1348,7 @@ class RadioMenuButton<T> extends StatelessWidget { ...@@ -1332,6 +1348,7 @@ class RadioMenuButton<T> extends StatelessWidget {
this.statesController, this.statesController,
this.clipBehavior = Clip.none, this.clipBehavior = Clip.none,
this.trailingIcon, this.trailingIcon,
this.closeOnActivate = true,
required this.child, required this.child,
}); });
...@@ -1436,6 +1453,9 @@ class RadioMenuButton<T> extends StatelessWidget { ...@@ -1436,6 +1453,9 @@ class RadioMenuButton<T> extends StatelessWidget {
/// An optional icon to display after the [child] label. /// An optional icon to display after the [child] label.
final Widget? trailingIcon; final Widget? trailingIcon;
/// {@macro flutter.material.menu_anchor.closeOnActivate}
final bool closeOnActivate;
/// The widget displayed in the center of this button. /// The widget displayed in the center of this button.
/// ///
/// Typically this is the button's label, using a [Text] widget. /// Typically this is the button's label, using a [Text] widget.
...@@ -1483,6 +1503,7 @@ class RadioMenuButton<T> extends StatelessWidget { ...@@ -1483,6 +1503,7 @@ class RadioMenuButton<T> extends StatelessWidget {
), ),
clipBehavior: clipBehavior, clipBehavior: clipBehavior,
trailingIcon: trailingIcon, trailingIcon: trailingIcon,
closeOnActivate: closeOnActivate,
child: child, child: child,
); );
} }
......
...@@ -2799,6 +2799,82 @@ void main() { ...@@ -2799,6 +2799,82 @@ void main() {
expect(radioValue, 1); expect(radioValue, 1);
}); });
}); });
testWidgets('MenuItemButton respects closeOnActivate property', (WidgetTester tester) async {
final MenuController controller = MenuController();
await tester.pumpWidget(
MaterialApp(
home: Material(
child: Center(
child: MenuAnchor(
controller: controller,
menuChildren: <Widget> [
MenuItemButton(
onPressed: () {},
child: const Text('Button 1'),
),
],
builder: (BuildContext context, MenuController controller, Widget? child) {
return FilledButton(
onPressed: () {
controller.open();
},
child: const Text('Tap me'),
);
},
),
),
),
)
);
await tester.tap(find.text('Tap me'));
await tester.pump();
expect(find.byType(MenuItemButton), findsNWidgets(1));
// Taps the MenuItemButton which should close the menu
await tester.tap(find.text('Button 1'));
await tester.pump();
expect(find.byType(MenuItemButton), findsNWidgets(0));
await tester.pumpAndSettle();
await tester.pumpWidget(
MaterialApp(
home: Material(
child: Center(
child: MenuAnchor(
controller: controller,
menuChildren: <Widget> [
MenuItemButton(
closeOnActivate: false,
onPressed: () {},
child: const Text('Button 1'),
),
],
builder: (BuildContext context, MenuController controller, Widget? child) {
return FilledButton(
onPressed: () {
controller.open();
},
child: const Text('Tap me'),
);
},
),
),
),
)
);
await tester.tap(find.text('Tap me'));
await tester.pump();
expect(find.byType(MenuItemButton), findsNWidgets(1));
// Taps the MenuItemButton which shouldn't close the menu
await tester.tap(find.text('Button 1'));
await tester.pump();
expect(find.byType(MenuItemButton), findsNWidgets(1));
});
} }
List<Widget> createTestMenus({ List<Widget> createTestMenus({
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment