简体   繁体   中英

Flutter Scaffold.of(context).openDrawer() doesn't work

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();
                    },
                  ),
                ],
              ),
          ),
        ],
      ),
    );
  }
}

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.

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

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 .

Scaffold.of(context).openEndDrawer()

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(),
                        ),
                      ],
                    ),
                  ],
                )),
      ),

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"),
    ),
  );
}

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();

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(
     ///...

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