简体   繁体   中英

Flutter change Drawer state using RiverPod State management

by using RiverPod State management, which i try to work on self improvment to learn and how can i use that i made a simple project and i'm trying to open Drawer by pressing on icon in AppBar which that's on another class and file, unfortunately doing like with RiverPod sample code my code doesn't work correctly and main class don't trigger on clicking on icon

simply i want to open drawer by clicking icon on AppBar

main file:

void main() {
  runApp(ProviderScope(child: MyApp()));
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Riverpod Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();

  @override
  Widget build(BuildContext context) {
    final drawerState = StateNotifierProvider<DrawerVisibility>((_)=>DrawerVisibility());
    return Consumer(
      builder: (context, read, _) {
        final state = read(drawerState.state);
        print('CLICKED $state');
        if(state){
          _scaffoldKey.currentState.openDrawer();
        }
        return Scaffold(
          key: _scaffoldKey,
          appBar: MyAppBar(),
          drawer: Drawer(),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text(
                  'You have pushed the button this many times:',
                ),
              ],
            ),
          ),
        );
      },
    );
  }
}

AppBar class file content:

class MyAppBar extends StatelessWidget with PreferredSizeWidget {
  @override
  Widget build(BuildContext context) {
    final drawerState = StateNotifierProvider<DrawerVisibility>((_)=>DrawerVisibility());
    return AppBar(
      automaticallyImplyLeading: false,
      title: Row(
        mainAxisAlignment: MainAxisAlignment.start,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: <Widget>[
          IconButton(icon: Icon(Icons.menu), onPressed: () {
            context.read(drawerState).changeDrawerState();
          }),
          Text('My Sample'),
        ],
      ),
    );
  }

  @override
  Size get preferredSize => Size.fromHeight(kToolbarHeight);
}

and finally RiverPod class

class DrawerVisibility extends StateNotifier {
  DrawerVisibility() : super(false);

  void changeDrawerState() => state = true;
}

another issue is when i start application in first time i get this output:

I/flutter (12240): CLICKED false
I/flutter (12240): CLICKED false

without any click on icon

instead of Consumer you should try using ProviderListener , its better when you want to show dialogs, snackbars, push/pop, or in this case opening a drawer. Finally instead of creating a final provider inside each build method, just create it once as a final global parameter so in each widget you read/watch it it uses the same instance

/// Create a final global StateNotifierProvider in your file instead of one inside each widget
final drawerState = StateNotifierProvider<DrawerVisibility>((_)=>DrawerVisibility());

class _MyHomePageState extends State<MyHomePage> {
  GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();

  @override
  Widget build(BuildContext context) {
    return ProviderListener<bool>(
      onChange: (context, state) {
        if(state) _scaffoldKey.currentState.openDrawer();
        //maybe check if the _scaffoldKey is mounted or is the drawer open before doing something
      },
      provider: drawerState.state,
      child: Scaffold(
        key: _scaffoldKey,
        appBar: MyAppBar(),
        drawer: Drawer(),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text(
                'You have pushed the button this many times:',
              ),
            ],
          ),
        ),
      ),
    );
  }
}

And in MyAppBar delete the drawerState so it uses the same global that your HomePage , also when closing the drawer at some point you should make the state false again

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM