5

I want to display a SnackBar in my Flutter app. I have read the docs and copyed it:
The body of my scaffold:

Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async => false,
      child: Scaffold(
        appBar: AppBar(
          centerTitle: true,
          title: Text("Osztályok"),
          leading: Padding(
              padding: const EdgeInsets.only(left: 5.0),
              child: IconButton(
                  icon: Icon(Icons.exit_to_app, color: Colors.white70),
                  onPressed: () {
                    authService.signOut();
                    authService.loggedIn = false;
                    Navigator.push(
                        context,
                        MaterialPageRoute(
                            builder: (context) => GoogleSignUp()));
                  })),
          actions: <Widget>[
            Padding(
                padding: const EdgeInsets.only(right: 5.0),
                child: Row(
                  children: <Widget>[
                    IconButton(
                        icon: Icon(Icons.add_circle_outline,
                            color: Colors.white70),
                        onPressed: () {
                          createPopup(context);
                        }),
//                    IconButton(
//                        icon: Icon(Icons.search, color: Colors.black38),
//                        onPressed: null),
                  ],
                )),
          ],
        ),

The SnackBarPage class:

class SnackBarPage extends StatelessWidget {

  void jelszopress(TextEditingController jelszoController, BuildContext context) async{
    var jelszo;
    DocumentReference docRef =   
    Firestore.instance.collection('classrooms').document(globals.getid());
    await docRef.get().then((value) => jelszo= (value.data['Jelszo']) );
    if (jelszo == jelszoController.text.toString()){
      Navigator.push(context,
          MaterialPageRoute(builder: (context) => InClassRoom()));
    }
    else{
      Navigator.pop(context);


      final snackBar = SnackBar(content: Text('Yay! A SnackBar!'));

      Scaffold.of(context).showSnackBar(snackBar);
    }
  }
Future<String> jelszoba(BuildContext context) {
    TextEditingController jelszoController = TextEditingController();
    return showDialog(
        context: context,
        builder: (context) {
          return AlertDialog(
              title: Text('Add meg a jelszót'),
              content: Container(
                  decoration: BoxDecoration(
                    borderRadius: BorderRadius.all(Radius.circular(20)),
                  ),
                  child: TextField(
                      controller: jelszoController,
                      decoration: InputDecoration(hintText: "Jelszó")
                  )
              ),
              actions: <Widget>[
                MaterialButton(
                  elevation: 5.0,
                  child: Text('Mehet'),
                  onPressed: () {
                    jelszopress(jelszoController, context);
                  },
                )]);
        }
    );
  }

  var nevek;
  var IDS;
  SnackBarPage(this.nevek, this.IDS);
  @override
  Widget build(BuildContext context){
    return ListView.builder(
      itemCount: nevek.length,
      itemBuilder: (context, index) {
        return Card(
          child: ListTile(
            onTap: () {
              globals.setid(IDS[index]);
              jelszoba(context);

            },
            title: Text(nevek[index]),
          ),
        );
      },
    ) ;

  }
}

But my cody doesn't display the SnackBar. I tried the solution of this question: How to properly display a Snackbar in Flutter? but adding a Builder widget didn't help.

jdsflk
  • 417
  • 9
  • 23

3 Answers3

4

"Scaffold.of(context)" has been deprecated, will return null. Now use "ScaffoldMessenger.of(context)". As per Flutter documentation.

  @override
  Widget build(BuildContext context) {
// here, Scaffold.of(context) returns null
    return Scaffold(
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            ScaffoldMessenger.of(context).showSnackBar(SnackBar(
              content: const Text('snack'),
              duration: const Duration(seconds: 1),
              action: SnackBarAction(
                label: 'ACTION',
                onPressed: () { },
              ),
            ));
          },
          child: const Text('SHOW SNACK'),
        ),
      ),
    );
  }

NOTE: Make sure your main.dart overrided build() function should return "MaterialApp" as a widget, such as:

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
   // Must be MaterialApp widget for ScaffoldMessenger support.
  return MaterialApp(  
      title: 'My App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyDashboard(),
    );
  }
}
H. Goyal
  • 160
  • 2
  • 12
1

So based on the error, it would seem that the context passed in Snackbar.of() is not the correct context. This would make sense based on 1 & 2; and summary copied below:

Each widget has its own BuildContext, which becomes the parent of the widget returned by the StatelessWidget.build or State.build function. (And similarly, the parent of any children for RenderObjectWidgets.)

In particular, this means that within a build method, the build context of the widget of the build method is not the same as the build context of the widgets returned by that build method.

So this means that the build context you are passing in jelszoba(context) function is not the build context you need and is actually the build context of the widget that is instantiating the Scaffold.

So How to Fix: To fix this wrap your Card widget in your SnackbarPage in a Builder widget and pass the context from it, to the jelszoba(context) method.

An example from 1 I post below:

@override
Widget build(BuildContext context) {
// here, Scaffold.of(context) returns null
return Scaffold(
  appBar: AppBar(title: Text('Demo')),
  body: Builder(
    builder: (BuildContext context) {
      return FlatButton(
        child: Text('BUTTON'),
        onPressed: () {
          // here, Scaffold.of(context) returns the locally created Scaffold
          Scaffold.of(context).showSnackBar(SnackBar(
            content: Text('Hello.')
          ));
        }
      );
    }
  )
);
}
Mohammad Assad Arshad
  • 1,535
  • 12
  • 14
1

You can normally use snack bar in the Bottom Navigation bar in this way. However, if you want to show it in the body, then just copy the code from Builder and paste it in the body of the scaffold.

      Scaffold(bottomNavigationBar: Builder(builder: (context) => Container(child: Row(children: <Widget>[
      Icon(Icons.add_alarm), Icon(Icons.map),    IconButton(icon: Icon(Icons.bookmark),
            onPressed:() {
        Scaffold.of(context).showSnackBar(mySnackBar);
            
              final mySnackBar =  SnackBar(
              shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
              behavior: SnackBarBehavior.floating,
              backgroundColor: Colors.white, duration: Duration(seconds: 1),
              content: Text(
                'Article has been removed from bookmarks',
                
              ),);
        } 
),
    ],
),
),
),
);

Note: In the behaviour property of SnackBar, you can just leave it empty. But the problem with that is "If you have Curved Navigation Bar or you have a floating action button above the bottom navigation bar, then the snackbar will lift these icons (or FAB ) and will affect the UI". That's why SnackBar.floating is more preferred as it is more capatible with the UI. But you can check and see on your own which suits you the best.

GAURAV JOSHI
  • 659
  • 8
  • 7