one Drawer for all screens in flutter web - flutter

i'm new to flutter and I want to create a web app with drawer and couple of screens.
here is my main function and root of apps ui:
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Tapchi Admin Panel',
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: bgColor,
textTheme: GoogleFonts.poppinsTextTheme(Theme
.of(context)
.textTheme)
.apply(bodyColor: Colors.white),
canvasColor: secondaryColor,
),
home: const DashboardScreen()
);
}
}
and here is my DashboardScreen:
class DashboardScreen extends StatelessWidget {
const DashboardScreen({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
);
}
}
and here is my SideMenu:
class SideMenu extends StatelessWidget {
const SideMenu({super.key});
#override
Widget build(BuildContext context) {
return Drawer(
child: ListView(
children: [
const DrawerHeader(child: Icon(Icons.android)),
SideMenuItem(
title: 'dashboard',
leadingIcon: Icons.dashboard,
press: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const DashboardScreen()));
}),
SideMenuItem(
title: 'users',
leadingIcon: Icons.person,
press: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const UserScreen()));
}),
],
),
);
}
}
my problem is when i navigate into DashboardScreen i lose AppBar and Drawer but I want to have them for entire application!.
in android we could solve this problem by using NavHost.
how can I have one Drawer for my whole app.
by the way i'm developing a webApp

Ok, I managed to do that using two MaterialApp widgets and a global navigatorKey variable. Here is an example:
import 'package:flutter/material.dart';
final navigatorKey = GlobalKey<NavigatorState>();
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return Sample();
}
}
class Sample extends StatelessWidget {
const Sample({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
drawer: SideMenu(),
// use new MaterialApp to push new (sub)screens on top of that area and preserve the same drawer
body: MaterialApp(
navigatorKey: navigatorKey,
home: MyHomePage(),
),
),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Center(child: Text('Home screen')),
),
);
}
}
class SideMenu extends Drawer {
const SideMenu({super.key});
#override
Widget build(BuildContext context) {
return Drawer(
child: Column(
children: [
const DrawerHeader(child: Icon(Icons.android)),
SideMenuItem(
title: 'dashboard',
leadingIcon: Icons.dashboard,
press: () {
Navigator.push(
navigatorKey.currentContext!,
MaterialPageRoute(
builder: (context) => const DashboardScreen()));
}),
SideMenuItem(
title: 'users',
leadingIcon: Icons.person,
press: () {
Navigator.push(
navigatorKey.currentContext!,
MaterialPageRoute(
builder: (context) => const UserScreen()));
}),
],
),
);
}
}
class SideMenuItem extends StatelessWidget {
final String title;
final IconData leadingIcon;
final Function() press;
const SideMenuItem({
super.key,
required this.title,
required this.leadingIcon,
required this.press,
});
#override
Widget build(BuildContext context) {
return ListTile(
leading: Icon(leadingIcon),
title: Text(title),
onTap: press,
);
}
}
class DashboardScreen extends StatelessWidget {
const DashboardScreen({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
color: Colors.red,
child: Center(child: Text('Dashboard screen')),
),
);
}
}
class UserScreen extends StatelessWidget {
const UserScreen({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
color: Colors.blue,
child: Center(child: Text('User screen')),
),
);
}
}

Related

How to Refresh State from Navigator Pop in Flutter

I want to refresh the state when calling Navigator Pop / Navigator Pop Until.
While I was doing some research, I finally found this article Flutter: Refresh on Navigator pop or go back. From the code in the article, it can work fine.
But there is a problem when I use the widget tree, for example like the code below:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Refresh on Go Back',
home: HomePage(),
);
}
}
Home Page - Parent Class
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int id = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Data: $id',
style: Theme.of(context).textTheme.headline5,
),
ButtonWidget(),
],
),
),
);
}
void refreshData() {
id++;
}
onGoBack(dynamic value) {
refreshData();
setState(() {});
}
}
Button Widget - Widget Class
class ButtonWidget extends StatelessWidget{
#override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (context) =>
SecondPage())).then(onGoBack);
// The Problem is Here
// How to call a Method onGoBack from HomePage Class
}
);
}
}
SecondPage
class SecondPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Second Page'),
),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Go Back'),
),
),
);
}
}
Or is there another solution to refresh the state class when calling Navigator Pop / Navigator Pop Until?
re-write your Button's class like this:
class ButtonWidget extends StatelessWidget{
final Function onGoBack;
ButtonWidget({this.onGoBack})
#override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (context) =>
SecondPage())).then(onGoBack);
//to avoid any np exception you can do this: .then(onGoBack ?? () => {})
// The Problem is Here
// How to call a Method onGoBack from HomePage Class
}
);
}
}
And add the onGoBack function as a parameter from the home page like this:
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int id = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Data: $id',
style: Theme.of(context).textTheme.headline5,
),
ButtonWidget(onGoBack: onGoBack),
],
),
),
);
}
void refreshData() {
id++;
}
onGoBack(dynamic value) {
refreshData();
setState(() {});
}
}
you must sent function on widget
class ButtonWidget extends StatelessWidget{
final Function(dynamic)? refresh;
const ButtonWidget({this.refresh})
#override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: ()async {
await Navigator.push(context, MaterialPageRoute(builder: (context) =>
SecondPage()));
if(refresh!=null){
refresh!("your params");
}
// The Problem is Here
// How to call a Method onGoBack from HomePage Class
}
);
}
}
and you can use widget
ButtonWidget(
refresh:onGoBack
)
Try this, it just you are calling method out of scope
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Refresh on Go Back',
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int id = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Data: $id',
style: Theme.of(context).textTheme.headline5,
),
ButtonWidget(
refresh: onGoBack,
)
],
),
),
);
}
void refreshData() {
id++;
}
onGoBack(dynamic value) {
refreshData();
setState(() {});
}
}
class ButtonWidget extends StatelessWidget {
final Function(dynamic)? refresh;
ButtonWidget({Key? key, this.refresh}) : super(key: key);
#override
Widget build(BuildContext context) {
print(refresh);
return RaisedButton(onPressed: () async {
await Navigator.push(
context, MaterialPageRoute(builder: (context) => SecondPage()))
.then((value) => refresh!("okay"));
});
}
}
class SecondPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Second Page'),
),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Go Back'),
),
),
);
}
}

Flutter: How to use Markdown in showDialog?

I'm trying to use Markdown (from package flutter_markdown: ^0.6.6) in a dialog box. Following example returns error:
RenderShrinkWrappingViewport does not support returning intrinsic
dimensions.
This is my code:
import 'package:flutter/material.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Package flutter_markdown'),
),
body: Center(
child: HelpButtonWithDialog(
title: 'markdown test',
content: '# Help Text\n\n* Text line 1\n*Text Line 2',
),
),
);
}
}
class HelpButtonWithDialog extends StatelessWidget {
final String title;
final String content;
HelpButtonWithDialog({
required this.title,
required this.content,
});
#override
Widget build(BuildContext context) {
return IconButton(
icon: Icon(Icons.help_outline),
onPressed: () => showDialog(
barrierDismissible: true,
context: context,
builder: (BuildContext ctx) => AlertDialog(
title: Text(title),
content: Markdown(
data: content,
shrinkWrap: true,
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: Text('OK'),
)
],
),
),
);
}
}
I found a workaround by using Dialog and copying parts from AlertDialog. I also filed an enhancement request https://github.com/flutter/flutter/issues/89464 to the Flutter team to get this proper.
Here is the workaround code:
import 'package:flutter/material.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Package flutter_markdown'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'flutter_markdown: Please add example how to use in showDialog'),
Text('https://github.com/flutter/flutter/issues/89464'),
HelpButtonWithDialog(
title: 'markdown test',
content: '# Help Text\n\n* Text line 1\n* Text Line 2',
),
],
),
),
);
}
}
class HelpButtonWithDialog extends StatelessWidget {
final String title;
final String content;
HelpButtonWithDialog({
required this.title,
required this.content,
});
#override
Widget build(BuildContext context) {
final ThemeData theme = Theme.of(context);
final DialogTheme dialogTheme = DialogTheme.of(context);
return IconButton(
icon: Icon(Icons.help_outline),
onPressed: () => showDialog(
barrierDismissible: true,
context: context,
builder: (BuildContext ctx) => Dialog(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
padding: EdgeInsets.fromLTRB(24.0, 24.0, 24.0, 24.0),
child: DefaultTextStyle(
style:
dialogTheme.titleTextStyle ?? theme.textTheme.headline6!,
child: Text(title),
),
),
MarkdownBody(
data: content,
shrinkWrap: true,
),
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: Text('OK'),
),
],
),
),
),
);
}
}

Pass data to multiple screens with inheritedwidget

There are some confusions about InheritedWidget that I don't understand.
I have searched and read some QAs about InheritedWidget on stackoverflow, but there are still things that I don't understand.
First of all, let's create a scenario.
This is my InheritedWidget:
class MyInheritedWidget extends InheritedWidget {
final String name;
MyInheritedWidget({
#required this.name,
#required Widget child,
Key key,
}) : super(key: key, child: child);
#override
bool updateShouldNotify(MyInheritedWidget oldWidget) =>
oldWidget.name != this.name;
static MyInheritedWidget of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>();
}
}
and this is MyHomePage that contains the MyInheritedWidget. MyInheritedWidget has two children: WidgetA and a button that navigates to another screen, in this case Page1.
class MyHomePage extends StatefulWidget {
#override
State createState() => new MyHomePageState();
}
class MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),
),
body: Center(
child: MyInheritedWidget(
name: 'Name',
child: Column(
children: [
WidgetA(),
TextButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => Page1(),
),
);
},
child: Text('Go to page 1'),
)
],
),
),
),
);
}
}
Inside WidgetA there is a text widget that displays the name field from MyInheritedWidget and another button that navigates to Page2.
class WidgetA extends StatefulWidget {
#override
_WidgetAState createState() => _WidgetAState();
}
class _WidgetAState extends State<WidgetA> {
#override
Widget build(BuildContext context) {
final myInheritedWidget = MyInheritedWidget.of(context);
return Column(
children: [
Text(myInheritedWidget.name),
TextButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => Page2(),
),
);
},
child: Text('Go to page 2'),
)
],
);
}
}
Page1 and Page2 each has only a text widget that displays the name field from MyInheritedWidget.
class Page1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
final myInheritedWidget = MyInheritedWidget.of(context);
return Scaffold(
appBar: AppBar(
title: Text('Page 1'),
),
body: Text(myInheritedWidget.name),
);
}
}
class Page2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
final myInheritedWidget = MyInheritedWidget.of(context);
return Scaffold(
appBar: AppBar(
title: Text('Page 2'),
),
body: Text(myInheritedWidget.name),
);
}
}
In this scenario, the name field of MyInheritedWidget is not accessible form Page1 and Page2, but it can be accessed in WidgetA.
Now lets get to the question:
It is said that an InheritedWidget can be accessed from all of its descendants. What does descendant mean?
In MyHomePage, I know WidgetA is a descendant of MyInheritedWidget. but, is Page1 also a descendant of MyInheritedWidget?
If the answer is no, How can I make Page1 a descendant of MyInheritedWidget?
Do I need to wrap it again inside MyInheritedWidget?
What if there is a chain of navigations like this: Page1-> Page2 -> Page3 ... Page10 and I want to access MyInheritedWidget in Page10, Do I have to wrap each of the pages inside MyInheritedWidget?
As #pskink says, MyHomePage pushes Page1, which is a descendant of Navigator, which is under MaterialApp, not MyInheritedWidget. The easiest solution is to create MyInheritedWidget above MaterialApp. This is my code (using ChangeNotifierProvider instead of MyInheritedWidget).
void main() {
setupLocator();
runApp(DevConnectorApp());
}
class DevConnectorApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
final log = getLogger('DevConnectorApp');
return MultiProvider(
providers: [
ChangeNotifierProvider<AuthService>(
create: (ctx) => AuthService(),
),
ChangeNotifierProxyProvider<AuthService, ProfileService>(
create: (ctx) => ProfileService(),
update: (ctx, authService, profileService) =>
profileService..updateAuth(authService),
),
],
child: Consumer<AuthService>(builder: (ctx, authService, _) {
log.v('building MaterialApp with isAuth=${authService.isAuth}');
return MaterialApp(
Here is an example using multiple Navigators to scope the InheritedWidget. The widget ContextWidget creates an InheritedWidget and a Navigator and has child widgets for the screens in your example.
class InheritedWidgetTest extends StatefulWidget {
#override
State createState() => new InheritedWidgetTestState();
}
class InheritedWidgetTestState extends State<InheritedWidgetTest> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),
),
body: Center(
child: Column(
children: [
ContextWidget('First'),
ContextWidget('Second'),
],
),
),
);
}
}
class ContextWidget extends StatelessWidget {
Navigator _getNavigator(BuildContext context, Widget child) {
return new Navigator(
onGenerateRoute: (RouteSettings settings) {
return new MaterialPageRoute(builder: (context) {
return child;
});
},
);
}
final name;
ContextWidget(this.name);
#override
Widget build(BuildContext context) {
return MyInheritedWidget(
name: this.name,
child: Expanded(
child: _getNavigator(
context,
PageWidget(),
),
),
);
}
}
class PageWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Column(
children: [
WidgetA(),
TextButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => Page1(),
),
);
},
child: Text('Go to page 1'),
)
],
);
}
}

Where to write the network call in Flutter?

I have a BottomNavigationBar with 3 tabs. Consider I select a product in an e-commerce app from the pages inside the first BottomNavigationBarItem. I need to see that product in the second BottomNavigationBarItem(cart page). I have written the network call code in initState() of second BottomNavigationBarItem; but it will not be called when I go to that page and I can't see the recently added product to the cart. Is it better to write them in the build method itself? Writing them in the build method calls it every time I go to other tabs also.
Use FutureBuilder or StreamBuilder to network call and flow the data to UI
Hope this will help you
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: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _selectedPage = 0;
String _selectedProduct;
Widget getCurrentPage(){
switch(_selectedPage){
case 0:
return Page1((selectedProduct){
setState((){
this._selectedProduct = selectedProduct;
_selectedPage=1;
});});
case 1:
return Page2(this._selectedProduct);
case 2:
return Page3();
default:
return Center(child:Text('Error'));
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: getCurrentPage(),
bottomNavigationBar: BottomNavigationBar(
onTap: (index){
setState((){
_selectedPage = index;
});
},
currentIndex: _selectedPage,
items: ['tab 1', 'tab 2', 'tab3'].map((e)=>BottomNavigationBarItem(
icon: Container(),
title: Text(e),
)).toList(),),
);
}
}
class Page1 extends StatelessWidget {
final Function(String) onProductClick;
const Page1(this.onProductClick);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title:Text('Page 1')),
body:Column(
children: <Widget>[
RaisedButton(
child: Text('Product 1'),onPressed: ()=>onProductClick('Product 1'),),
RaisedButton(
child: Text('Product 2'),onPressed: ()=>onProductClick('Product 2'),),
RaisedButton(
child: Text('Product 3'),onPressed: ()=>onProductClick('Product 3'),),
RaisedButton(
child: Text('Product 4'),onPressed: ()=>onProductClick('Product 4'),),
RaisedButton(
child: Text('Product 5'),onPressed: ()=>onProductClick('Product 5'),),
],)
);
}
}
class Page2 extends StatelessWidget {
final String selectedProduct;
const Page2(this.selectedProduct);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title:Text('Page 2')),
body:Center(child:Text(selectedProduct??'Nothing selected'))
);
}
}
class Page3 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title:Text('Page 3')),
body:Center(child:Text('Page 3'))
);
}
}

How to keep the widget's state in Scaffold.drawer in Flutter?

I want to keep the widget's state in Scaffold.drawer. The Scaffold.drawer is a custom widget, which has a RaiseButton in it.
When click the button, the text in the button changed.
But when the drawer is closed, and reopen the drawer, the changed text is reseted.
I have use " with AutomaticKeepAliveClientMixin<> " in my custom Drawer, but it does't work.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Flutter Demo"),
),
drawer: Drawer(child: CustomDrawer(),),
body: Center(
child: Text("Flutter Demo"),
),
);
}
}
class CustomDrawer extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _CustomDrawerState();
}
}
class _CustomDrawerState extends State<CustomDrawer> with AutomaticKeepAliveClientMixin<CustomDrawer> {
String btnText = "Click!";
#override
bool get wantKeepAlive => true;
#override
Widget build(BuildContext context) {
super.build(context);
return Center(
child: RaisedButton(onPressed: () {
setState(() {
btnText = "Clicked!!";
});
}, child: Text(btnText),),
);
}
}
I expect the widget's state can keep, even if the Drawer is closed.
Create a separate widget for the drawer and just use in anywhere you need to.
Manage the Drawer State with a Provider
class DrawerStateInfo with ChangeNotifier {
int _currentDrawer = 0;
int get getCurrentDrawer => _currentDrawer;
void setCurrentDrawer(int drawer) {
_currentDrawer = drawer;
notifyListeners();
}
void increment() {
notifyListeners();
}
}
Adding State Management to the Widget tree
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MultiProvider(
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.teal,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
),
providers: <SingleChildCloneableWidget>[
ChangeNotifierProvider<DrawerStateInfo>(
builder: (_) => DrawerStateInfo()),
],
);
}
}
Creating The Drawer Widget for reuse in application
class MyDrawer extends StatelessWidget {
MyDrawer(this.currentPage);
final String currentPage;
#override
Widget build(BuildContext context) {
var currentDrawer = Provider.of<DrawerStateInfo>(context).getCurrentDrawer;
return Drawer(
child: ListView(
children: <Widget>[
ListTile(
title: Text(
"Home",
style: currentDrawer == 0
? TextStyle(fontWeight: FontWeight.bold)
: TextStyle(fontWeight: FontWeight.normal),
),
trailing: Icon(Icons.arrow_forward),
onTap: () {
Navigator.of(context).pop();
if (this.currentPage == "Home") return;
Provider.of<DrawerStateInfo>(context).setCurrentDrawer(0);
Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (BuildContext context) =>
MyHomePage(title: "Home")));
},
),
ListTile(
title: Text(
"About",
style: currentDrawer == 1
? TextStyle(fontWeight: FontWeight.bold)
: TextStyle(fontWeight: FontWeight.normal),
),
trailing: Icon(Icons.arrow_forward),
onTap: () {
Navigator.of(context).pop();
if (this.currentPage == "About") return;
Provider.of<DrawerStateInfo>(context).setCurrentDrawer(1);
Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (BuildContext context) => MyAboutPage()));
},
),
],
),
);
}
}
Use of Drawer in one of your pages
class MyAboutPage extends StatefulWidget {
#override
_MyAboutPageState createState() => _MyAboutPageState();
}
class _MyAboutPageState extends State<MyAboutPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('About Page'),
),
drawer: MyDrawer("About"),
);
}
}
In your case, you have 2 choices:
You should keep your state in your Top level widget. in your case _MyHomePageState;
Use state managers like Redux, Bloc, ScopedModel. I think ScopedModel is great for you in this case.
otherwise, you can't control the state of Drawer. cause it re-creates every moment you call the Drawer by the action button in Appbar;