Is it possible to detect when a Drawer is open so that we can run some routine to update its content?
A typical use case I have would be to display the number of followers, likers... and for this, I would need to poll the server to get this information, then to display it.
I tried to implement a NavigatorObserver to catch the moment when the Drawer is made visible/hidden but the NavigatorObserver does not detect anything about the Drawer.
Here is the code linked to the NavigatorObserver:
import 'package:flutter/material.dart';
typedef void OnObservation(Route<dynamic> route, Route<dynamic> previousRoute);
typedef void OnStartGesture();
class NavigationObserver extends NavigatorObserver {
OnObservation onPushed;
OnObservation onPopped;
OnObservation onRemoved;
OnObservation onReplaced;
OnStartGesture onStartGesture;
@override
void didPush(Route<dynamic> route, Route<dynamic> previousRoute) {
if (onPushed != null) {
onPushed(route, previousRoute);
}
}
@override
void didPop(Route<dynamic> route, Route<dynamic> previousRoute) {
if (onPopped != null) {
onPopped(route, previousRoute);
}
}
@override
void didRemove(Route<dynamic> route, Route<dynamic> previousRoute) {
if (onRemoved != null)
onRemoved(route, previousRoute);
}
@override
void didReplace({ Route<dynamic> oldRoute, Route<dynamic> newRoute }) {
if (onReplaced != null)
onReplaced(newRoute, oldRoute);
}
@override
void didStartUserGesture() {
if (onStartGesture != null){
onStartGesture();
}
}
}
and the initialization of this observer
void main(){
runApp(new MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
final NavigationObserver _observer = new NavigationObserver()
..onPushed = (Route<dynamic> route, Route<dynamic> previousRoute) {
print('** pushed route: $route');
}
..onPopped = (Route<dynamic> route, Route<dynamic> previousRoute) {
print('** poped route: $route');
}
..onReplaced = (Route<dynamic> route, Route<dynamic> previousRoute) {
print('** replaced route: $route');
}
..onStartGesture = () {
print('** on start gesture');
};
@override
void initState(){
super.initState();
}
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Title',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new SplashScreen(),
routes: <String, WidgetBuilder> {
'/splashscreen': (BuildContext context) => new SplashScreen(),
},
navigatorObservers: <NavigationObserver>[_observer],
);
}
}
Thanks for your help.
When a user opens the drawer, Flutter adds the drawer to the navigation stack. Therefore, to close the drawer, call Navigator. pop(context) .
To disable the drawer edge swipe, set the Scaffold. drawerEnableOpenDragGesture to false. Then, use ScaffoldState. openDrawer to open the drawer and Navigator.
initState()
when open drawer by any action.dispose()
when close drawer by any action.class MyDrawer extends StatefulWidget {
@override
_MyDrawerState createState() => _MyDrawerState();
}
class _MyDrawerState extends State<MyDrawer> {
@override
void initState() {
super.initState();
print("open");
}
@override
void dispose() {
print("close");
super.dispose();
}
@override
Widget build(BuildContext context) {
return Drawer(
child: Column(
children: <Widget>[
Text("test1"),
Text("test2"),
Text("test3"),
],
),
);
}
}
If you are altering state with these functions to rebuild drawer items, you may encounter the error: Unhandled Exception: setState() or markNeedsBuild() called during build
.
This can be handled by using the following two functions in initState() source
Option 1
WidgetsBinding.instance.addPostFrameCallback((_){
// Add Your Code here.
});
Option 2
SchedulerBinding.instance.addPostFrameCallback((_) {
// add your code here.
});
Full Example of Option 1
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
// Your Code Here
});
}
Best solution
ScaffoldState
has a useful method isDrawerOpen
which provides the status of open/close.
Example: Here on the back press, it first checks if the drawer is open, if yes then first it will close before exit.
/// create a key for the scaffold in order to access it later.
GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
@override
Widget build(context) {
return WillPopScope(
child: Scaffold(
// assign key (important)
key: _scaffoldKey,
drawer: SideNavigation(),
onWillPop: () async {
// drawer is open then first close it
if (_scaffoldKey.currentState.isDrawerOpen) {
Navigator.of(context).pop();
return false;
}
// we can now close the app.
return true;
});}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With