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

- 1,605
- 4
- 14
- 25
-
Do you want it to be accessible by swipe? – Mohit Shetty Sep 01 '19 at 17:49
-
No, i want to disable the touch sliding, i want to open it programatically only – krishnaji Sep 02 '19 at 14:21
8 Answers
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 ...
)

- 237,138
- 77
- 654
- 440
-
Thanks for your answer, sorry it is not tapping it is sliding, how to disable that sliding, i want to open it pro-grammatically only – krishnaji Sep 01 '19 at 17:58
-
You're very smart, you simply changed the question, it was tapping initially and now sliding. – CopsOnRoad Sep 01 '19 at 18:00
-
AFAIK, there is no way to stop the drawer from opening by sliding, that's against Material Guidelines, what you can do is you can create your own custom drawer to achieve that effect. – CopsOnRoad Sep 01 '19 at 18:07
-
2Yes i changed the question, because of my wrong asking, sorry for that, can you please provide a source to build custom drawer – krishnaji Sep 02 '19 at 07:14
-
When I open the drawer using this method, I can't pop the drawer using the navigator. How would I go about solving that? – Isak Feb 29 '20 at 15:34
-
@Isak Not sure how you're doing that, it should work. Would you mind posting it as a question? – CopsOnRoad Feb 29 '20 at 16:03
-
1This should be the accepted answer, as the accepted answer disables swipe to open, which is in fact unwanted behaviour. – Sjoerd Van Den Berg Apr 20 '21 at 09:15
- 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.
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.

- 2,200
- 20
- 26
-
By itself the code was not working, it was meant as a suggestion, I've updated the answer again with a self contained fully working demo, tested on an emulated pixel 2 with OSX and android studio :) – giulp May 29 '21 at 09:26
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 ...
)

- 389
- 3
- 8
-
I'm some cases (like ours) like if you are handling global shortcuts, you may need to use a GlobalKey() but what you are suggesting is the preferred approach if you are inside of the scaffold. – Venkat D. Dec 10 '20 at 19:19
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(),
),
),
],
),
),
);
}
}

- 4,225
- 1
- 29
- 34
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();
}
},
),
],
),

- 2,013
- 10
- 18
-
I know this is a pretty old question, but this really spurs a "best-practices" question in me - do most people develop a single-page app model, with one scaffold across the whole app, or give each page its own full build with its own scaffold, and page->route between them? – ChrisH Apr 03 '20 at 20:36
-
1@ChrisH: this would be worth a separate question, don't you think? – Daniel Leiszen May 16 '20 at 22:08
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,
),
)

- 2,976
- 19
- 25
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();

- 554
- 3
- 17
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;
},
),
));
}
}

- 71
- 4