Skip to content

Instantly share code, notes, and snippets.

@Abhilash-Chandran
Created March 22, 2020 14:17
Show Gist options
  • Save Abhilash-Chandran/668f5722ce13c97d153d965ec3ad23e5 to your computer and use it in GitHub Desktop.
Save Abhilash-Chandran/668f5722ce13c97d153d965ec3ad23e5 to your computer and use it in GitHub Desktop.
NestedMenu Flutter
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
body: Row(
children: <Widget>[
MainMenu(title: 'Menu 1'),
CustomMenu(title: 'Menu 2', rootMenu: true),
],
)),
);
}
}
enum WhyFarther { harder, smarter, selfStarter, tradingCharter }
class MainMenu extends StatefulWidget {
MainMenu({Key key, this.title}) : super(key: key);
final String title;
@override
_MainMenuState createState() => _MainMenuState();
}
class _MainMenuState extends State<MainMenu> {
WhyFarther _selection = WhyFarther.smarter;
@override
Widget build(BuildContext context) {
// This menu button widget updates a _selection field (of type WhyFarther,
// not shown here).
return Padding(
padding: const EdgeInsets.all(2.0),
child: PopupMenuButton<WhyFarther>(
child: Material(
textStyle: Theme.of(context).textTheme.subtitle1,
elevation: 2.0,
child: Container(
padding: EdgeInsets.all(8),
child: Text(widget.title),
),
),
onSelected: (WhyFarther result) {
setState(() {
_selection = result;
});
},
itemBuilder: (BuildContext context) => <PopupMenuEntry<WhyFarther>>[
const PopupMenuItem<WhyFarther>(
value: WhyFarther.harder,
child: Text('Working a lot harder'),
),
const PopupMenuItem<WhyFarther>(
value: WhyFarther.smarter,
child: Text('Being a lot smarter'),
),
const PopupMenuItem<WhyFarther>(
value: WhyFarther.selfStarter,
child: SubMenu('Sub Menu is too long'),
),
const PopupMenuItem<WhyFarther>(
value: WhyFarther.tradingCharter,
child: Text('Placed in charge of trading charter'),
),
],
),
);
}
}
class SubMenu extends StatefulWidget {
final String title;
const SubMenu(this.title);
@override
_SubMenuState createState() => _SubMenuState();
}
class _SubMenuState extends State<SubMenu> {
WhyFarther _selection = WhyFarther.smarter;
@override
Widget build(BuildContext context) {
// print(rendBox.size.bottomRight);
return PopupMenuButton<WhyFarther>(
child: Row(
children: <Widget>[
Text(widget.title),
Spacer(),
Icon(Icons.arrow_right, size: 30.0),
],
),
onCanceled: () {
if (Navigator.canPop(context)) {
Navigator.pop(context);
}
},
onSelected: (WhyFarther result) {
setState(() {
_selection = result;
});
},
// how much the submenu should offset from parent. This seems to have an upper limit.
offset: Offset(300, 0),
itemBuilder: (BuildContext context) => <PopupMenuEntry<WhyFarther>>[
const PopupMenuItem<WhyFarther>(
value: WhyFarther.harder,
child: Text('Working a lot harder'),
),
const PopupMenuItem<WhyFarther>(
value: WhyFarther.smarter,
child: Text('Being a lot smarter'),
),
const PopupMenuItem<WhyFarther>(
value: WhyFarther.selfStarter,
child: Text('Being a lot smarter'),
),
const PopupMenuItem<WhyFarther>(
value: WhyFarther.tradingCharter,
child: Text('Placed in charge of trading charter'),
),
],
);
}
}
class CustomMenu extends StatefulWidget {
const CustomMenu({Key key, this.title, this.rootMenu=false}) : super(key: key);
final String title;
final bool rootMenu;
@override
_CustomMenuState createState() => _CustomMenuState();
}
class _CustomMenuState extends State<CustomMenu> {
WhyFarther _selection = WhyFarther.smarter;
@override
Widget build(BuildContext context) {
// This menu button widget updates a _selection field (of type WhyFarther,
// not shown here).
return Padding(
padding: const EdgeInsets.all(2.0),
child: GestureDetector(
onTap: () {
// This offset should depend on the largest text and this is tricky when
// the menu items are changed
Offset offset = widget.rootMenu?Offset.zero:Offset(-300,0);
final RenderBox button = context.findRenderObject();
final RenderBox overlay =
Overlay.of(context).context.findRenderObject();
final RelativeRect position = RelativeRect.fromRect(
Rect.fromPoints(
button.localToGlobal(Offset.zero, ancestor: overlay),
button.localToGlobal(button.size.bottomRight(Offset.zero),
ancestor: overlay),
),
offset & overlay.size,
);
showMenu(
context: context,
position: position,
items: <PopupMenuEntry<WhyFarther>>[
const PopupMenuItem<WhyFarther>(
value: WhyFarther.harder,
child: Text('Working a lot harder'),
),
const PopupMenuItem<WhyFarther>(
value: WhyFarther.smarter,
child: Text('Being a lot smarter'),
),
const PopupMenuItem<WhyFarther>(
value: WhyFarther.selfStarter,
child: CustomMenu(title: 'Sub Menu long'),
),
const PopupMenuItem<WhyFarther>(
value: WhyFarther.tradingCharter,
child: Text('Placed in charge of trading charter'),
),
]).then((selectedValue){
// do something with the value
if(Navigator.canPop(context)) Navigator.pop(context);
});
},
child: Material(
textStyle: Theme.of(context).textTheme.subtitle1,
elevation: widget.rootMenu?2.0:0.0,
child: Padding(
padding: widget.rootMenu? EdgeInsets.all(8.0):EdgeInsets.all(0.0),
child: Row(
children: <Widget>[
Text(widget.title),
if(!widget.rootMenu)
Spacer(),
if(!widget.rootMenu)
Icon(Icons.arrow_right),
],
),
),)
),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment