Flutter: How to open Drawer programmatically - flutter

I want to open Drawer programmatically not by sliding it, how to disable that sliding functionality (touch functionality of Drawer)

Null safe code
Using GlobalKey:
final GlobalKey<ScaffoldState> _key = GlobalKey(); // Create a key
#override
Widget build(BuildContext context) {
return Scaffold(
key: _key, // Assign the key to Scaffold.
drawer: Drawer(),
floatingActionButton: FloatingActionButton(
onPressed: () => _key.currentState!.openDrawer(), // <-- Opens drawer
),
);
}
Using Builder:
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: Drawer(),
floatingActionButton: Builder(builder: (context) {
return FloatingActionButton(
onPressed: () => Scaffold.of(context).openDrawer(), // <-- Opens drawer.
);
}),
);
}
If you want to disable opening the Drawer using a drag gesture, you can set
Scaffold(
drawerEnableOpenDragGesture: false
// above code ...
)

To disable the slide to open functionality you can set the property drawerEnableOpenDragGesture on Scaffold to false.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
// this to prevent the default sliding behaviour
drawerEnableOpenDragGesture: false,
drawer: Drawer(),
appBar: AppBar(
leading: Builder(builder: (context) => // Ensure Scaffold is in context
IconButton(
icon: Icon(Icons.menu),
onPressed: () => Scaffold.of(context).openDrawer()
),
),
)
)
);
}
}
To open the drawer programmatically using Scaffold.of(context) you'll have to ensure (thanks Krolaw !) that the context inside which the call is made is aware of the Scaffold.
A clean way to do it is to wrap the button in a builder.
I've edited the answer to include a minimal full working example.
Scaffold is a widget that implements material design principles, so be aware that to be able to call this method, you'll need to import 'package:flutter/material.dart'; and your widget needs to have a MaterialApp as ancestor.
Codepen demo
As with many Flutter things, there are other solutions to ensure Scaffold is in context.
Error messages are IMO among the best features of flutter framework, allow me to humbly suggest to always read them thoroughly and to explore the documentation they point at.
For instance, this is part of the error message that one gets if calling openDrawer outside of a proper context:
Scaffold.of() called with a context that does not contain a Scaffold.
No Scaffold ancestor could be found starting from the context that was passed to Scaffold.of(). This usually happens when the context provided is from the same StatefulWidget as that whose build function actually creates the Scaffold widget being sought.
There are several ways to avoid this problem. The simplest is to use a Builder to get a context that is "under" the Scaffold. For an example of this, please see the documentation for Scaffold.of():
https://api.flutter.dev/flutter/material/Scaffold/of.html
A more efficient solution is to split your build function into several widgets. This introduces a new context from which you can obtain the Scaffold. In this solution, you would have an outer widget that creates the Scaffold populated by instances of your new inner widgets, and then in these inner widgets you would use Scaffold.of().
A less elegant but more expedient solution is assign a GlobalKey to the Scaffold, then use the key.currentState property to obtain the ScaffoldState rather than using the Scaffold.of() function.

Calling Scaffold.of doesn't work because the context doesn't contain the Scaffold. Some solutions above have ignored this, others have used GlobalKey. I believe the cleanest solution is wrapping the button in a Builder:
Scaffold(
drawerEnableOpenDragGesture: false, // Prevent user sliding open
appBar: AppBar(
automaticallyImplyLeading: false,
title: Text("Some Title"),
actions: [
Builder(builder: (context) => // Ensure Scaffold is in context
IconButton(
icon: Icon(Icons.settings),
onPressed: () => Scaffold.of(context).openDrawer()
)),
],
),
// TODO ...
)

Here is another example of opening the drawer programmatically from a hamburger icon and without the Appbar:-
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() => MyAppState();
}
class MyAppState extends State<MyApp> {
var scaffoldKey = GlobalKey<ScaffoldState>();
#override
Widget build(BuildContext context) {
return new MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
key: scaffoldKey,
drawer: new Drawer(
child: new ListView(
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Text('Drawer Header'),
decoration: BoxDecoration(
color: Colors.blue,
),
),
ListTile(
title: Text('Item 1'),
onTap: () {
//Do some stuff here
//Closing programmatically - very less practical use
scaffoldKey.currentState.openEndDrawer();
},
)
],
),
),
body: Stack(
children: <Widget>[
new Center(
child: new Column(
children: <Widget>[],
)),
Positioned(
left: 10,
top: 20,
child: IconButton(
icon: Icon(Icons.menu),
onPressed: () => scaffoldKey.currentState.openDrawer(),
),
),
],
),
),
);
}
}

appBar: AppBar(
automaticallyImplyLeading: false,
title: Text(
"Infilon Technologies",
style:
TextStyle(fontFamily: "Poppins", fontWeight: FontWeight.w600),
),
actions: <Widget>[
IconButton(
icon: Icon(Icons.menu),
onPressed: () {
if (_scaffoldKey.currentState.isEndDrawerOpen) {
_scaffoldKey.currentState.openDrawer();
} else {
_scaffoldKey.currentState.openEndDrawer();
}
},
),
],
),

If you are using endDrawer (right to left) in Scaffold, you should use:
Scaffold.of(context).openEndDrawer();
If you are using drawer (left to right) in Scaffold, you should use:
Scaffold.of(context).openDrawer();

You can use this perfect method to open drawer
its Worked with null safty module above flutter 2.12
class DashBoardScreen extends StatefulWidget {
final String? screen;
const DashBoardScreen(this.screen, {super.key});
#override
State<DashBoardScreen> createState() => _DashBoardScreenState();
}
class _DashBoardScreenState extends State<DashBoardScreen> {
DashBoardScreenController controller =
Get.put(getIt<DashBoardScreenController>());
#override
Widget build(BuildContext context) {
controller.scaffoldKey = GlobalKey<ScaffoldState>();
return Obx(() => Scaffold(
key: controller.scaffoldKey,
onDrawerChanged: (isOpened) {
if (!isOpened) {
setState(() {});
}
},
appBar: AppBar(
title: const Text("Test drawer App"),
actions: const [
const Padding(
padding: EdgeInsets.only(right: 20),
child: Icon(Icons.search))
],
leading: UnconstrainedBox(
child: GestureDetector(
onTap: () {
controller.scaffoldKey.currentState!.openDrawer();
},
child: const AbsorbPointer(
absorbing: true,
child: SizedBox(
height: 50,
child: CircleAvatar(
backgroundImage: CachedNetworkImageProvider(
"https://cdn.pixabay.com/photo/2014/07/09/10/04/man-388104_960_720.jpg",
)),
),
),
),
),
),
drawerEdgeDragWidth:
kIsWeb ? MediaQuery.of(context).size.width * 0.2 : null,
drawer: Drawer(
key: controller.scaffoldKey,
child: ListView(
children: [
DropdownMenuItem(onTap: () {}, child: const Text("Add Anime"))
],
)),
body: widget.screen == StringVariables.ADD_ANIME
? AddAnimeFragment(widget.screen!)
: Container(),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Add Anime',
),
BottomNavigationBarItem(
icon: Icon(Icons.business),
label: 'Favourite',
),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
label: 'Settings',
),
],
currentIndex: controller.bottomSheetIndex.value,
selectedItemColor: ColorName.primaryColor,
onTap: (s) {
controller.bottomSheetIndex.value = s;
},
),
));
}
}

Simply flow these steps
create a variable in class like this
var scaffoldKey = GlobalKey<ScaffoldState>();
then use this key in your scaffold like this
Scaffold(
key: scaffoldKey,
appBar: AppBar(
automaticallyImplyLeading: false,
leading: IconButton(
onPressed: () {
scaffoldKey.currentState?.openDrawer();
},
icon: Icon(
Icons.menu,
color: ExtraColors.PRIMARY_800,
)),
title: Text(
'${AppStrings.appName}',
),
centerTitle: true,
),
)

Related

No Scaffold widget found when use BottomSheet

I am just learning Flutter and got stuck on this error:
No Scaffold widget found.
Home widgets require a Scaffold widget ancestor.
The specific widget that could not find a Scaffold ancestor was: Home
The ancestors of this widget were
but as you can see from my code I do have a Scaffold and I played around adding it wherever I can but I didn't work for.
What can be the reason to what I've done or didn't notice there?
import 'package:firebase_redux_app/services/firebase.auth.dart';
import 'package:flutter/material.dart';
// import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_redux_app/services/firestore.dart';
import 'package:provider/provider.dart';
import 'package:firebase_redux_app/screens/home/brewList.dart';
import 'package:firebase_redux_app/models/brew.dart';
class Home extends StatelessWidget {
final AuthService _auth = AuthService();
#override
Widget build(BuildContext context) {
void _showSettingsPanel() {
showBottomSheet(
context: context,
builder: (context) {
return Container(
padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 60.0),
child: Text('bottom sheet'),
);
});
}
return StreamProvider<List<Brew>>.value(
value: DBFirestore().brews,
child: Scaffold(
backgroundColor: Colors.brown[50],
appBar: AppBar(
title: Text('Brew Crew'),
backgroundColor: Colors.brown[400],
elevation: 0.0,
actions: <Widget>[
FlatButton.icon(
onPressed: () async {
await _auth.signOut();
},
icon: Icon(Icons.person),
label: Text('Log Out')),
FlatButton.icon(
icon: Icon(Icons.settings),
label: Text('settings'),
onPressed: () => _showSettingsPanel(),
)
],
),
body: BrewList(),
),
);
}
}
This error is caused because of the scope of your _showSettingsPanel method
There are 2 things you can do
1.
Make the _showSettingsPanel a method in the Home class and allow it take the context as a parameter. Hence, wrap your settings FlatButton in a Builder and pass the context to the _showSettingsPanel method.
Like this
class Home extends StatelessWidget {
void _showSettingsPanel(context) {
showBottomSheet(
context: context,
builder: (context) {
return Container(
padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 60.0),
child: Text('bottom sheet'),
);
});
}
#override
Widget build(BuildContext context) {
return StreamProvider<List<Brew>>(
value: DBFireStore().brews
child: Scaffold(
backgroundColor: Colors.brown[50],
appBar: AppBar(
title: Text('Brew Crew'),
backgroundColor: Colors.brown[400],
elevation: 0.0,
actions: <Widget>[
FlatButton.icon(
onPressed: () async {
},
icon: Icon(Icons.person),
label: Text('Log Out')),
Builder(
builder: (context) {
return FlatButton.icon(
icon: Icon(Icons.settings),
label: Text('settings'),
onPressed: () => _showSettingsPanel(context),
);
}
)
],
),
body: BrewList(),
),
);
}
}
2.
Wrap the Home widget in a Scaffold wherever you use it, instead of using just Home
Like this
Scaffold(body: Home())
now this prb has different solutions. U gotta use sccafoldKey
final _scaffoldKey = GlobalKey<ScaffoldState>();
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
actions: [
IconButton(
onPressed: () {
_scaffoldKey.currentState!.showBottomSheet(
(context) => const AddTaskScreen());
},
icon: const Icon(Icons.add))
],
),

How can I change Drawer icon in flutter?

The drawer has this default three horizontal bars as default icon but I want to change it to something else.
I have checked the possible options under the Drawer(), but no property seems to be attached to that.
This should work.
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title:Text('hi'),
leading: IconButton(
icon: Icon(Icons.accessible),
onPressed: () => Scaffold.of(context).openDrawer(),
),
),
);
From the docs ->
{Widget leading} Type: Widget
A widget to display before the [title].
If this is null and [automaticallyImplyLeading] is set to true, the [AppBar] will imply an appropriate widget. For example, if the [AppBar] is in a [Scaffold] that also has a [Drawer], the [Scaffold] will fill this widget with an [IconButton] that opens the drawer (using [Icons.menu]). If there's no [Drawer] and the parent [Navigator] can go back, the [AppBar] will use a [BackButton] that calls [Navigator.maybePop].
The following code shows how the drawer button could be manually specified instead of relying on [automaticallyImplyLeading]:
import 'package:flutter/material.dart';
Widget build(context) {
return AppBar(
leading: Builder(
builder: (BuildContext context) {
return IconButton(
icon: const Icon(Icons.menu),
onPressed: () {
Scaffold.of(context).openDrawer();
},
tooltip: MaterialLocalizations.of(context).openAppDrawerTooltip,
);
},
),
);
}
The [Builder] is used in this example to ensure that the context refers to that part of the subtree. That way this code snippet can be used even inside the very code that is creating the [Scaffold] (in which case, without the [Builder], the context wouldn't be able to see the [Scaffold], since it would refer to an ancestor of that widget).
appBar: AppBar(
leading: Builder(
builder: (context) => IconButton(
icon: Icon(Icons.menu_rounded),
onPressed: () => Scaffold.of(context).openDrawer(),
),
),
title: Text(
"Track your Shipment",
),
),
You can open a drawer with a custom button like this too.
create this scaffold key.
var scaffoldKey = GlobalKey<ScaffoldState>();
now added a scaffolled in your state class like this
#override
Widget build(BuildContext context) {
return Scaffold(
key: scaffoldKey,
drawer: Drawer(
child: Text('create drawer widget tree here'),
),
appBar: AppBar(
backgroundColor: Colors.white,
title: Text(
'appName',
style: Theme.of(context).textTheme.headline2,
),
leading: IconButton(
onPressed: () {
scaffoldKey.currentState?.openDrawer();
},
icon: Image.asset(
'assets/images/menu.png',
fit: BoxFit.cover,
),
),
),
body: Container(),
);
}
Lets say you have: index.dart (where you want to use the appbar), drawer.dart (your drawer or navigation menu) and appbar.dart (your appbar)
you can do this in drawer:
Widget drawer(BuildContext context) {
return Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
Container(
...
)
);
then your appbar.dart:
class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
#override
Widget build(BuildContext context) {
return AppBar(
backgroundColor: Colors.white,
leading: InkWell(
onTap: () => Scaffold.of(context).openDrawer(),
child: Image.asset("assets/images/imgAppBar.png"),
),
title: Container(...
then your index.dart:
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
drawer: drawer(context),
appBar: CustomAppBar(),
...
this is just a simple one. You can use IconButton in case you want to use an Icon etc.
You need to create the Global key of type ScaffoldKey the use that to open the drawer and change the icon too:
Widget build(BuildContext context) {
var scaffoldKey = GlobalKey<ScaffoldState>();
return Scaffold(
key: scaffoldKey,
appBar: AppBar(
title:Text('hi'),
leading: IconButton(
icon: Icon(Icons.accessible),
onPressed: () => scafoldKey.currentState.openDrawer(),
),
),
);
Actually, i tried the answer by cmd_prompter and it didn't work for me.
The better approach is described here
My working code is here:
return DefaultTabController(
key: Key("homePage"),
length: 2,
child: Scaffold(
endDrawer: Drawer(
),
appBar: AppBar(
leading: BackButton(
onPressed: () {
},
),
title: Text(profile.selectedCity!),
actions: [
Padding(
padding: EdgeInsets.symmetric(horizontal: baseUnit(3)),
child: Builder(
builder: (context) => IconButton(
icon: Icon(Icons.account_circle),
onPressed: () => Scaffold.of(context).openEndDrawer(),
)
)
)
It worked fine for me - especially this part regarding using Builder. This is important - otherwise it was not working for me.
class HomeOne extends StatefulWidget { const HomeOne({Key? key}) : super(key: key);
#override State createState() =>HomeOneState(); }
var scaffoldKey = GlobalKey();
class HomeOneState extends State { #override Widget build(BuildContext context) { var theme = Theme.of(context); return Directionality( textDirection: TextDirection.rtl, child: Scaffold( key: scaffoldKey, drawerEnableOpenDragGesture: true, // drawerScrimColor: Colors.red, appBar: AppBar( leading: IconButton( onPressed: () => scaffoldKey.currentState?.openDrawer(), icon: const Icon( Icons.add, color: Colors.red, )), ),
AppBar(
leading: IconButton(
onPressed: () {
// Code
},
icon: Icon(Icons.arrow_back),
),
),
To only change the icon color, it's easier to do by adding an iconTheme to the AppBar:
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: Drawer(),
appBar: AppBar(
title: Text("Navigation Drawer"),
iconTheme: IconThemeData(color: Colors.green),
),
);
}

How to show popup menu on any icon in Flutter?

I want a popup menu or some kind of slide screen with options to come when i click on an icon in the app bar, however i dont want to use PopMenuButton as i dont want to use that icon. How can I do this?
My code
return new Scaffold(
appBar: new AppBar(
title: new Text("Home"),
leading: IconButton(
icon: Icon(
Icons.dehaze,
color: Colors.black,
),
onPressed: () {
// do something
},
),
),
body: new Center(...),
);
#Denise, you don't need to manually create a button and assign action for drawer menu. You can simply use drawer in Scaffold with Drawer widget like so,
class MyAppState extends State<MyApp> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Test'),
),
drawer: Drawer(
// Add a ListView to the drawer. This ensures the user can scroll
// through the options in the drawer if there isn't enough vertical
// space to fit everything.
child: ListView(
// Important: Remove any padding from the ListView.
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Text('Drawer Header'),
decoration: BoxDecoration(
color: Colors.blue,
),
),
ListTile(
title: Text('Item 1'),
onTap: () {
// Update the state of the app
// ...
// Then close the drawer
Navigator.pop(context);
},
),
ListTile(
title: Text('Item 2'),
onTap: () {
// Update the state of the app
// ...
// Then close the drawer
Navigator.pop(context);
},
),
],
),
),
body: Padding(
padding: EdgeInsets.all(20.0),
child: Center(
child: Column(
children: <Widget>[
Text('')
],
)
)
),
)
);
}
}
And if you wanna use different icon,
class MyAppState extends State<MyApp> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: Text('Test'),
leading: new IconButton(
icon: new Icon(Icons.dehaze),
onPressed: () => _scaffoldKey.currentState.openDrawer()),
),
drawer: Drawer(......
Hope this helps.
If the icon is the problem in PopMenuButton. You can change it by assigning icon attribute in PopMenuButton.
PopupMenuButton<Choice>(
onSelected: _select,
icon:Icon(
Icons.dehaze,
color: Colors.black,
),
itemBuilder: (BuildContext context) {
return choices.skip(2).map((Choice choice) {
return PopupMenuItem<Choice>(
value: choice,
child: Text(choice.title),
);
}).toList();
https://flutter.dev/docs/catalog/samples/basic-app-bar

flutter setstate rebuild only one child

in flutter I need that when I call setstate, it only rebuilds a widget
I put 2 children in a stack, I need that when a button is pressed, only the second one is rebuilt.
bool popup = false;
Scaffold(
appBar: AppBar(
title: const Text('TEST'),
actions: <Widget>[
IconButton( // + BUTTON
icon: Icon(Icons.add),
onPressed: () {
setState(() {
popup = true;
});
},
),
IconButton( // - BUTTON
icon: Icon(Icons.remove),
onPressed: () {
setState(() {
popup = false;
});
),
],
),
body: SafeArea(
child: Stack(
children: <Widget>[
Container( // FIRST WIDGET
key: ValueKey(1),
child: Text("Random - "+new Random().nextInt(20).toString())
),
popup ? Center(child: Text("abc")) : Text("") , // SECOND WIDGET
],
),
),
);
I expect that when I press the "+" button only the second widget will be re-built, but now it will rebuild all the contents of the stack.
thank you all.
From the official docs we can read:
"When setState() is called on a State, all descendent widgets rebuild. Therefore, localize the setState() call to the part of the subtree whose UI actually needs to change. Avoid calling setState() high up in the tree if the change is contained to a small part of the tree."
My suggestion, and I use it most of the times, is separate the widget that you want to rebuild in a new StatefulWidget. This way the setState only will be rebuild that widget.
class MyAppBar extends StatefulWidget
...
class _MyAppBarState extends State<MyAppBar> {
bool popup = false;
#override
Widget build(BuildContext context) {
return AppBar(
title: const Text('TEST'),
actions: <Widget>[
IconButton( // + BUTTON
icon: Icon(Icons.add),
onPressed: () {
setState(() {
popup = true;
});
},
),
IconButton( // - BUTTON
icon: Icon(Icons.remove),
onPressed: () {
setState(() {
popup = false;
});
),
],
),
}
Then call it in your Scaffold:
Scaffold(
appBar: MyAppBar(),
Other method I can suggest is using ValueNotifier or notifyListeners(). Please read this page Avoid rebuilding all the widgets repetitively. It is well explained.
Another option is to use ValueListenableBuilder:
class _MyHomePageState extends State<MyHomePage> {
final ValueNotifier<bool> popup = ValueNotifier<bool>(false);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('TEST'),
actions: <Widget>[
IconButton(
// + BUTTON
icon: Icon(Icons.add),
onPressed: () {
popup.value = true;
}),
IconButton(
// - BUTTON
icon: Icon(Icons.remove),
onPressed: () {
popup.value = false;
})
],
),
body: Center(
child: ValueListenableBuilder<bool>(
valueListenable: popup,
builder: (context, value, _) {
return Stack(
children: [
Text("Random - " + new Random().nextInt(20).toString()),
popup.value ? Center(child: Text("abc")) : Text(""),
],
);
}),
),
);
}
}
You can use StreamBuilder:
StreamController<bool> popup = StreamController<bool>();
#override
void dispose() {
popup.close();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('TEST'),
actions: <Widget>[
IconButton( // + BUTTON
icon: Icon(Icons.add),
onPressed: () => popup.add(true),
),
IconButton( // - BUTTON
icon: Icon(Icons.remove),
onPressed: () => popup.add(false),
),
],
),
body: SafeArea(
child: Stack(
children: <Widget>[
Container( // FIRST WIDGET
key: ValueKey(1),
child: Text("Random - "+new Random().nextInt(20).toString())
),
StreamBuilder<bool>(
stream: popup.stream,
initialData: false,
builder: (cxt, snapshot) {
return snapshot.data ? Center(child: Text("abc")) : Text("");
},
)
],
),
),
);
}
Remove the setState from the widget you don't want to be changed. And only use setState for the ones you need to rebuild
Or you can consider using inheritedModel widget
Here is the example from where you can learn how to build an Inherited model widget to update only specific widgets rather than the whole widgets.
https://medium.com/flutter-community/flutter-state-management-setstate-fn-is-the-easiest-and-the-most-powerful-44703c97f035

Show back button instead of drawer button - flutter

I have a Flutter project which uses material design, that as I go through routes the appbar will show the backbutton. Recently, I just implemented a drawer in my project, and the drawer icon overrides the back icon. I essentially want to undo this, showing the back button, for certain screens, and show the menu button for other screens, almost like when I define the drawer having a showIcon: false property? I understand this post is a similar question, but no code is shown for the question or the solution... My drawer looks like this:
return Scaffold(
//appbar is here
appBar: AppBar(
title: Text("Title"),
),
drawer: drawer,
body: _buildBody(),
);
And I define drawer here:
var drawer = Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
//My listTiles and UserAccountsDrawerHeader are removed for simplicity
],
),
);
Thanks for any help.
Short answer:
AppBar(
leading: IconButton(
onPressed: () {}, // Handle your on tap here.
icon: Icon(Icons.arrow_back_ios),
),
)
Screenshot:
Full code:
void main() => runApp(MaterialApp(home: MyPage()));
class MyPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Column(
children: <Widget>[
ElevatedButton(
onPressed: () => Navigator.push(context, MaterialPageRoute(builder: (_) => Page1())),
child: Text("Go to Drawer Page"),
),
ElevatedButton(
onPressed: () => Navigator.push(context, MaterialPageRoute(builder: (_) => Page2())),
child: Text("Go to Back button Page"),
),
],
),
),
);
}
}
// This has drawer
class Page1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
drawer: Drawer(),
);
}
}
// This has back button and drawer
class Page2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () => Navigator.pop(context),
),
),
drawer: Drawer(),
);
}
}
AppBar(
leading: Builder(
builder: (BuildContext context) {
return IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () { Navigator.pop(context); },
);
},
),
)