Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter: possible to detect when a drawer is open?

Tags:

flutter

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.

like image 595
boeledi Avatar asked Apr 22 '18 11:04

boeledi


People also ask

How do you automatically close drawers in Flutter?

When a user opens the drawer, Flutter adds the drawer to the navigation stack. Therefore, to close the drawer, call Navigator. pop(context) .

How do I turn off swipe in drawer in Flutter?

To disable the drawer edge swipe, set the Scaffold. drawerEnableOpenDragGesture to false. Then, use ScaffoldState. openDrawer to open the drawer and Navigator.


2 Answers

Detecting & Running Functions When Drawer Is Opened / Closed

  • Run initState() when open drawer by any action.
  • Run 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"),
                ],
            ),
        );
    }
}

State Management Considerations

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
    });
}
like image 166
pepen Avatar answered Sep 20 '22 13:09

pepen


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;
  });}
like image 22
Vivek Bansal Avatar answered Sep 20 '22 13:09

Vivek Bansal