Reputation: 183
I need to achieve a list of PopUpMenu nested inside a PopUpMenu. On click on one of the itmes I want to get another PopUpMenu with it's own items.
We could say it maight look similar to classic windows options.
Is it possible to achievie in flutter?
Upvotes: 2
Views: 4841
Reputation: 21
You can do like this, add it to code.
class PopupMenuChildrenItem<T> extends PopupMenuEntry<T> {
const PopupMenuChildrenItem({
super.key,
this.height = kMinInteractiveDimension,
this.padding,
this.enable = true,
this.textStyle,
this.onTap,
required this.itemBuilder,
required this.child,
});
final TextStyle? textStyle;
final EdgeInsets? padding;
final bool enable;
final void Function()? onTap;
final List<PopupMenuEntry<T>> Function(BuildContext) itemBuilder;
final Widget child;
@override
final double height;
@override
bool represents(T? value) => false;
@override
MyPopupMenuItemState<T, PopupMenuChildrenItem<T>> createState() => MyPopupMenuItemState<T, PopupMenuChildrenItem<T>>();
}
class MyPopupMenuItemState<T, W extends PopupMenuChildrenItem<T>> extends State<W> {
@protected
void handleTap(T value) {
widget.onTap?.call();
Navigator.pop<T>(context, value);
}
@override
Widget build(BuildContext context) {
final ThemeData theme = Theme.of(context);
final PopupMenuThemeData popupMenuTheme = PopupMenuTheme.of(context);
TextStyle style = widget.textStyle ??
popupMenuTheme.textStyle ??
theme.textTheme.subtitle1!;
return PopupMenuButton<T>(
enabled: widget.enable,
onSelected: handleTap,
itemBuilder: widget.itemBuilder,
child: AnimatedDefaultTextStyle(
style: style,
duration: kThemeChangeDuration,
child: Container(
alignment: AlignmentDirectional.centerStart,
constraints: BoxConstraints(minHeight: widget.height),
padding: widget.padding ?? const EdgeInsets.symmetric(horizontal: 16),
child: widget.child,
),
),
);
}
}
Then, use it like
PopupMenuButton<int>(
child: const Text('MENU'),
onSelected: (result) {
setState(() {
_selection = result;
});
},
itemBuilder: (BuildContext context) => [
PopupMenuChildrenItem(
child: const Text('SUBMENU A'),
itemBuilder: (BuildContext context) => [
const PopupMenuItem(
value: 1,
child: Text('1'),
),
const PopupMenuItem(
value: 2,
child: Text('2'),
),
],
),
PopupMenuChildrenItem(
child: const Text('SUBMENU B'),
itemBuilder: (BuildContext context) => [
const PopupMenuItem(
value: 3,
child: Text('3'),
),
const PopupMenuItem(
value: 4,
child: Text('4'),
),
],
),
const PopupMenuItem(
value: 5,
child: Text('5'),
),
const PopupMenuItem(
value: 6,
child: Text('6'),
),
],
)
Upvotes: 0
Reputation: 4577
Sure you can:
This show two subMenu with two items each.
I used an enum for the demo:
enum Item { i1, i2, i3, i4 }
Make sure to call Navigator.pop(context)
in the onSelected to close the first menu.
PopupMenuButton(
child: Text('MENU'),
itemBuilder: (BuildContext context) => <PopupMenuEntry<PopupMenuButton>>[
PopupMenuItem(
child: PopupMenuButton(
child: Text('SUBMENU A'),
onSelected: (Item result) {
setState(() { _selection = result; });
Navigator.pop(context); },
itemBuilder: (BuildContext context) => <PopupMenuEntry<Item>>[
const PopupMenuItem<Item>(
value: Item.i1,
child: Text('i1'),
),
const PopupMenuItem<Item>(
value: Item.i2,
child: Text('i2'),
),
],
),
),
PopupMenuItem(
child: PopupMenuButton(
child: Text('SUBMENU B'),
onSelected: (Item result) {
setState(() { _selection = result; });
Navigator.pop(context); },
itemBuilder: (BuildContext context) => <PopupMenuEntry<Item>>[
const PopupMenuItem<Item>(
value: Item.i3,
child: Text('i3'),
),
const PopupMenuItem<Item>(
value: Item.i4,
child: Text('i4'),
),
],
),
),
],
),
Upvotes: 3
Reputation: 692
you can get nested pop up menus like this :
PopupMenuButton(
itemBuilder: (_) {
return [
PopupMenuItem(child: Text("Item1")),
PopupMenuItem(
child: PopupMenuButton(
child: Text("Nested Items"),
itemBuilder: (_) {
return [
PopupMenuItem(child: Text("Item2")),
PopupMenuItem(child: Text("Item3"))
];
},
),
),
];
},
)
Upvotes: 2