Reputation: 781
I want to open a drawer after pushing on the custom button in BottomMenu I have trouble with Scaffold.of(context).openDrawer(), it doesn't work. My BottomMenu is a separate widget class. As I understand, it doesn't work because it's a separate context. How can I get the right context? Or perhaps someone knows another solution.
Here my code reproducer:
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(
title: 'Flutter Demo',
home: MyHomePage(title: 'Flutter Drawer'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
bottomNavigationBar: BottomMenu(),
endDrawer: SizedBox(
width: double.infinity,
child: Drawer(
elevation: 16,
child: Container(
color: Colors.black,
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
ListTile(
title: Text('Some context here',
style: TextStyle(color: Colors.white))),
ListTile(
title: Text('Some context here',
style: TextStyle(color: Colors.white))),
],
),
),
),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Call Drawer form menu reproducer',
)
],
),
),
);
}
}
class BottomMenu extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: Wrap(
alignment: WrapAlignment.center,
children: <Widget>[
Divider(color: Colors.black, height: 1),
Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
InkWell(
borderRadius: new BorderRadius.circular(20.0),
customBorder: Border.all(color: Colors.black),
child: Container(
padding: EdgeInsets.only(
left: 3, right: 6, bottom: 15, top: 11),
child: Row(
children: <Widget>[
Icon(Icons.menu),
Text('Show menu', style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold)),
],
),
),
onTap: () {
Scaffold.of(context).openDrawer();
},
),
],
),
),
],
),
);
}
}
Upvotes: 11
Views: 19080
Reputation: 11
I tried with this and worked
Builder(
builder: (BuildContext context) {
return IconButton(
onPressed: () {
Scaffold.of(context).openEndDrawer();
},
icon: const Icon(Icons.menu),
);
},
),
Upvotes: 0
Reputation: 15
class MyApp extends StatelessWidget {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey();
@override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: Text('My App'),
),
body: Center(
child: Text('This is the body of the app.'),
),
bottomNavigationBar: BottomMenu(scaffoldKey: _scaffoldKey),
);
}
}
class BottomMenu extends StatelessWidget {
final GlobalKey<ScaffoldState> scaffoldKey;
const BottomMenu({Key? key, required this.scaffoldKey}) : super(key: key);
@override
Widget build(BuildContext context) {
return BottomNavigationBar(
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
label: 'Settings',
),
],
onTap: (index) {
// Open the drawer when the settings button is tapped.
if (index == 1) {
scaffoldKey.currentState?.openDrawer();
}
},
);
}
}
Upvotes: 0
Reputation: 236
NOTE: ANY OTHER TYPE OF BUTTON WON'T WORK FOR INVOKING THE DRAWER
Must use IconButton
Example:
AppBar(leading: Builder(builder: (context) {
return IconButton(
icon:Text("Open Drawer"), // icon property is of type Widget
onPressed: () {
Scaffold.of(context).openDrawer();
},
);
}))
Best of Luck!
Upvotes: 0
Reputation: 81
you need wrap Builder, like this:
AppBar(
leading: Builder(
builder: (context) {
return IconButton(
icon: Icon(Icons.abc_outlined),
onPressed: () {
Scaffold.of(context).openDrawer();
},
);
}
),
//...//
Its working for me!
Upvotes: 2
Reputation: 1
Assign Drawer to drawer property in scaffold. Wrap your specific Widget/Button(where you want to open drawer on its click method) with Builder. Use below method on click property: enter image description here Scaffold.of(context).openDrawer();
Upvotes: 0
Reputation: 3264
The Problem
This issue can occur when you do not use the correct BuildContext
when calling Scaffold.of(context).openDrawer()
(or openEndDrawer()
).
Easiest Solution
Simply wrap whatever calls openDrawer()
(or openEndDrawer()
) with a Builder
widget. This will give it a working context
.
Minimal Working Example
// your build method
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: Builder(builder: (context) { // this uses the new context to open the drawer properly provided by the Builder
return FloatingActionButton(onPressed: (() => Scaffold.of(context).openDrawer()));
}),
drawer: const Drawer(
child: Text("MY DRAWER"),
),
);
}
Upvotes: 5
Reputation: 490
If you have the appbar widget with an action button to launch the drawer and the drawer is never pushed please remember that you need to define after appbar: ...
the endDrawer: YOURAppDrawerWIDGET(),
or else using the Scaffold.of(context).openEndDrawer()
will not work.
Scaffold(
appBar: AppBar(title: Text(_title)),
endDrawer: AppDrawer(), // <-- this is required or else it will not know what is opening
body: SingleChildScrollView(
///...
Upvotes: -1
Reputation: 687
In my case, this worked.
return Scaffold(
key: _scaffoldKey,
endDrawerEnableOpenDragGesture: false, // This!
appBar: AppBar(
iconTheme: IconThemeData(color: Colors.white),
leading: IconButton(
icon: Icon(Icons.menu, size: 36),
onPressed: () => _scaffoldKey.currentState.openDrawer(), // And this!
),
),
drawer: DrawerHome(),
....
and _scaffoldKey
must be initialized as,
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
under the class.
Upvotes: 21
Reputation: 52386
Similar problem here. Clicked on button and nothing happened. The problem is I was using the context of the widget that instantiated Scaffold. Not the context of a child of Scaffold.
Here is how I solved it:
// body: Column(
// children: <Widget>[
// Row(
// children: <Widget>[
// IconButton(
// icon: Icon(Icons.filter_list),
// onPressed: () => Scaffold.of(context).openEndDrawer(), (wrong context)
// ),
// ],
// ),
// ],
// )
To:
body: Builder(
builder: (context) => Column(
children: <Widget>[
Row(
children: <Widget>[
IconButton(
icon: Icon(Icons.filter_list),
onPressed: () => Scaffold.of(context).openEndDrawer(),
),
],
),
],
)),
),
Upvotes: 1
Reputation: 2073
My problem solved that instead of
Scaffold.of(context).openEndDrawer()
I give key to Scaffold and then I call by state like below
_scaffoldkey.currentState.openEndDrawer()
It solved my problem I hope It also works for you
Upvotes: 8
Reputation: 3091
The problem is that you specified endDrawer
on Scaffold
yet you're calling Scaffold.of(context).openDrawer()
.
openDrawer()
documentation states:
If the scaffold has a non-null Scaffold.drawer, this function will cause the drawer to begin its entrance animation.
Since your drawer
is null, nothing happens.
In contrast, openEndDrawer()
informs us:
If the scaffold has a non-null Scaffold.endDrawer, this function will cause the end side drawer to begin its entrance animation.
Since your endDrawer
is not null you should use openEndDrawer()
method. Alternatively, if you don't care which side the drawer slides in from, you can use drawer
instead of endDrawer
when building Scaffold
.
Upvotes: 11