mirror of
https://github.com/flutter/flutter
synced 2024-08-27 12:00:58 +00:00
Add option to keep ``MenuAnchor
` open after
`MenuItem
`` tap (#123723)
Add option to keep ```MenuAnchor``` open after ```MenuItem``` tap
This commit is contained in:
parent
63e30480cd
commit
9a344c2604
|
@ -810,6 +810,7 @@ class MenuItemButton extends StatefulWidget {
|
|||
this.clipBehavior = Clip.none,
|
||||
this.leadingIcon,
|
||||
this.trailingIcon,
|
||||
this.closeOnActivate = true,
|
||||
required this.child,
|
||||
});
|
||||
|
||||
|
@ -871,6 +872,14 @@ class MenuItemButton extends StatefulWidget {
|
|||
/// An optional icon to display after the [child] label.
|
||||
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.
|
||||
///
|
||||
/// Typically this is the button's label, using a [Text] widget.
|
||||
|
@ -1089,7 +1098,9 @@ class _MenuItemButtonState extends State<MenuItemButton> {
|
|||
void _handleSelect() {
|
||||
assert(_debugMenuInfo('Selected ${widget.child} menu'));
|
||||
widget.onPressed?.call();
|
||||
_MenuAnchorState._maybeOf(context)?._root._close();
|
||||
if (widget.closeOnActivate) {
|
||||
_MenuAnchorState._maybeOf(context)?._root._close();
|
||||
}
|
||||
}
|
||||
|
||||
void _createInternalFocusNodeIfNeeded() {
|
||||
|
@ -1140,6 +1151,7 @@ class CheckboxMenuButton extends StatelessWidget {
|
|||
this.statesController,
|
||||
this.clipBehavior = Clip.none,
|
||||
this.trailingIcon,
|
||||
this.closeOnActivate = true,
|
||||
required this.child,
|
||||
});
|
||||
|
||||
|
@ -1242,6 +1254,9 @@ class CheckboxMenuButton extends StatelessWidget {
|
|||
/// An optional icon to display after the [child] label.
|
||||
final Widget? trailingIcon;
|
||||
|
||||
/// {@macro flutter.material.menu_anchor.closeOnActivate}
|
||||
final bool closeOnActivate;
|
||||
|
||||
/// The widget displayed in the center of this button.
|
||||
///
|
||||
/// Typically this is the button's label, using a [Text] widget.
|
||||
|
@ -1292,6 +1307,7 @@ class CheckboxMenuButton extends StatelessWidget {
|
|||
),
|
||||
clipBehavior: clipBehavior,
|
||||
trailingIcon: trailingIcon,
|
||||
closeOnActivate: closeOnActivate,
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
@ -1332,6 +1348,7 @@ class RadioMenuButton<T> extends StatelessWidget {
|
|||
this.statesController,
|
||||
this.clipBehavior = Clip.none,
|
||||
this.trailingIcon,
|
||||
this.closeOnActivate = true,
|
||||
required this.child,
|
||||
});
|
||||
|
||||
|
@ -1436,6 +1453,9 @@ class RadioMenuButton<T> extends StatelessWidget {
|
|||
/// An optional icon to display after the [child] label.
|
||||
final Widget? trailingIcon;
|
||||
|
||||
/// {@macro flutter.material.menu_anchor.closeOnActivate}
|
||||
final bool closeOnActivate;
|
||||
|
||||
/// The widget displayed in the center of this button.
|
||||
///
|
||||
/// Typically this is the button's label, using a [Text] widget.
|
||||
|
@ -1483,6 +1503,7 @@ class RadioMenuButton<T> extends StatelessWidget {
|
|||
),
|
||||
clipBehavior: clipBehavior,
|
||||
trailingIcon: trailingIcon,
|
||||
closeOnActivate: closeOnActivate,
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2799,6 +2799,82 @@ void main() {
|
|||
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({
|
||||
|
|
Loading…
Reference in a new issue