14

I am trying to show a Snackbar on click of a floatingActionbutton. But when I click on the floatingactionbutton it's not showing anything. Here is my code. I am using a StatefulWidget. I debugged and checked that the onPressed function is also getting executed but somehow the Snackbar is not visible. What can be the root cause of the issue? I feel the BuildContext I am passing has some issue.

class MyApp extends StatefulWidget{
  @override
  MyAppState createState() {
    // TODO: implement createState
    return new MyAppState();
  }

}

class MyAppState extends State<MyApp>{
  File _image;
  String _text;

  Future getImage() async {
    var image = await ImagePicker.pickImage(source: ImageSource.camera);
    _image = image;
    final FirebaseVisionImage visionImage = FirebaseVisionImage.fromFile(_image);
    final TextRecognizer textRecognizer = FirebaseVision.instance.textRecognizer();
    final VisionText visionText = await textRecognizer.processImage(visionImage);

    String detectedText = visionText.text;

    setState(() {
      _image = image;
      _text = detectedText;
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: new AppBar(
          title: new Text('Image Picker Example'),
        ),
        body: new Center(
          child: _image == null
              ? new Text('No image selected.')
              : new Image.file(_image),
        ),
        floatingActionButton: new FloatingActionButton(
          onPressed: (){
            showSnackBar(context);
//            getImage();
          },
          tooltip: 'Pick Image',
          child: new Icon(Icons.add_a_photo),
        ),
      ),
    );
  }

  void showSnackBar(BuildContext context) {
    final scaffold = Scaffold.of(context);
    final snackBarContent = SnackBar(
      content: Text("sagar"),
      action: SnackBarAction(
          label: 'UNDO', onPressed: scaffold.hideCurrentSnackBar),
    );
    scaffold.showSnackBar(snackBarContent);
  }

}
Miguel Ruivo
  • 16,035
  • 7
  • 57
  • 87
sagar suri
  • 4,351
  • 12
  • 59
  • 122

4 Answers4

23

That happens because the BuildContext used has not a Scaffold ancestor thus, won't be able to find it to render a SnackBar since it's up to the Scaffold to display it.

According to the of method documentation:

When the Scaffold is actually created in the same build function, the context argument to the build function can't be used to find the Scaffold (since it's "above" the widget being returned). In such cases, the following technique with a Builder can be used to provide a new scope with a BuildContext that is "under" the Scaffold:

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text('Demo')
    ),
    body: Builder(
      // Create an inner BuildContext so that the onPressed methods
      // can refer to the Scaffold with Scaffold.of().
      builder: (BuildContext context) {
        return Center(
          child: RaisedButton(
            child: Text('SHOW A SNACKBAR'),
            onPressed: () {
              ScaffoldMessenger.of(context).showSnackBar(SnackBar(
                content: Text('Hello!'),
              ));
            },
          ),
        );
      },
    ),
  );
}

Solution

Wrapping your FloatingActionButton in a Builder widget will make it possible in a more elegant way than using a GlobalKey, which was already mentioned by the @Epizon answer.

Miguel Ruivo
  • 16,035
  • 7
  • 57
  • 87
11
class MyApp extends StatefulWidget{
  @override
  MyAppState createState() {
    // TODO: implement createState
    return new MyAppState();
  }

}

class MyAppState extends State<MyApp>{

  final GlobalKey<ScaffoldState> _scaffoldkey = new GlobalKey<ScaffoldState>();
  File _image;
  String _text;

  Future getImage() async {
    var image = await ImagePicker.pickImage(source: ImageSource.camera);
    _image = image;
    final FirebaseVisionImage visionImage = FirebaseVisionImage.fromFile(_image);
    final TextRecognizer textRecognizer = FirebaseVision.instance.textRecognizer();
    final VisionText visionText = await textRecognizer.processImage(visionImage);

    String detectedText = visionText.text;

    setState(() {
      _image = image;
      _text = detectedText;
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        key: _scaffoldkey,
        appBar: new AppBar(
          title: new Text('Image Picker Example'),
        ),
        body: new Center(
          child: _image == null
              ? new Text('No image selected.')
              : new Image.file(_image),
        ),
        floatingActionButton: new FloatingActionButton(
          onPressed: (){
            showSnackBar();
//            getImage();
          },
          tooltip: 'Pick Image',
          child: new Icon(Icons.add_a_photo),
        ),
      ),
    );
  }

  void showSnackBar() {
    final snackBarContent = SnackBar(
      content: Text("sagar"),
      action: SnackBarAction(
          label: 'UNDO', onPressed: _scaffoldkey.currentState.hideCurrentSnackBar),
    );
    _scaffoldkey.currentState.showSnackBar(snackBarContent);
  }



}
Epizon
  • 189
  • 6
4

To show SnackBar You can use like this:

 ScaffoldMessenger.of(context).showSnackBar(SnackBar(
          content: Text('User Logged In'),
        ));

Previous SnackBar was used like this:

Scaffold.of(context).showSnackBar(SnackBar(
                content: Text('Rahul Kushwaha!'),
              ));

Now, SnackBar is managed by ScaffoldMessenger. For details study this link

Rahul Kushwaha
  • 5,473
  • 3
  • 26
  • 30
1

I faced this issue when trying to showSnackbar() in StatfulWidget from second level child of the parent Parent() => childLevel1 => childOfLevel1(){showing the snackbar here}

I implemented @Epizon answer but .currentState.showSnackBar(snackBarContent); was deprecated, According to flutter:

The SnackBar API within the Scaffold is now handled by the ScaffoldMessenger read full document

so replacing this line in @Epizon answer: _scaffoldKey.currentState!.showSnackBar(_snackBarContent);

to this: ScaffoldMessenger.of(_scaffoldKey.currentState!.context) .showSnackBar(_snackBarContent);

will solve the deprecation issue

here is the code

final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();

    void _showSnack(String msg) {
      final _snackBarContent = SnackBar(content: Text(msg));
      ScaffoldMessenger.of(_scaffoldKey.currentState!.context)
          .showSnackBar(_snackBarContent);     
    }

return MaterialApp(
      home: Scaffold(
        //resizeToAvoidBottomInset: true,
        key: _scaffoldKey,
      body: Center(
child: ElevatedButton(
child: Text("show snackbar"),
onPressed(){_showSnack("im located in the btn's onPressed");},
);
);
Fathi Dev
  • 139
  • 2
  • 5