如何在 Flutter 中正确显示 Snackbar?

Posted

技术标签:

【中文标题】如何在 Flutter 中正确显示 Snackbar?【英文标题】:How to properly display a Snackbar in Flutter? 【发布时间】:2019-05-24 03:01:18 【问题描述】:

我试图在点击floatingActionbutton 时显示Snackbar。但是当我点击floatingactionbutton 时,它什么也没显示。这是我的代码。我正在使用StatefulWidget。我调试并检查了 onPressed 函数是否也在执行,但不知何故 Snackbar 不可见。问题的根本原因是什么?我觉得我传递的 BuildContext 有问题。

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


【问题讨论】:

【参考方案1】:

发生这种情况是因为使用的BuildContext 没有Scaffold 祖先,因此无法找到它来呈现SnackBar,因为它取决于Scaffold 来显示它。

根据of method 文档:

当 Scaffold 实际在同一个构建函数中创建时, 构建函数的上下文参数不能用于查找 脚手架(因为它在被返回的小部件“上方”)。在这样的 在这种情况下,可以使用以下带有 Builder 的技术来提供 具有位于脚手架“下方”的 BuildContext 的新范围:

@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!'),
              ));
            ,
          ),
        );
      ,
    ),
  );

解决方案

将您的 FloatingActionButton 包装在 Builder 小部件中将比使用 @Epizon 答案中已经提到的 GlobalKey 更优雅。

【讨论】:

【参考方案2】:
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);
  




【讨论】:

【参考方案3】:

显示SnackBar你可以这样使用:

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

以前的SnackBar是这样使用的:

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

现在,SnackBar 由 ScaffoldMessenger 管理。有关详细信息,请研究此link

【讨论】:

【参考方案4】:

在最新版本中--

完整示例


import 'package:flutter/material.dart';


void test() 
  runApp(MyApp());


class MyApp extends StatelessWidget 
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      title: 'Test App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: testPage(title: 'Flutter Demo Home Page'),
    );
  


class testPage extends StatefulWidget 
  testPage(Key? key, required this.title) : super(key: key);

  final String title;

  @override
  _testPageState createState() => _testPageState();


class _testPageState extends State<testPage> 

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

  @override
  Widget build(BuildContext context) 
    return MaterialApp(

        home: SizedBox(
            child: Scaffold(

                key: _scaffoldKey,

                body: Center(
                    child: RaisedButton(
                      shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(10.0),
                      ),
                      onPressed: () 

                        final snackBar = SnackBar(content: Text('Your Text'));

                        _scaffoldKey.currentState!.showSnackBar(snackBar);
                      ,

                      child: Text("Show SB"),
                    )
                )
            )
        )
    );
  



  [1]: https://i.stack.imgur.com/hKQYZ.jpg

【讨论】:

以上是关于如何在 Flutter 中正确显示 Snackbar?的主要内容,如果未能解决你的问题,请参考以下文章

Flutter - 如何在一行中显示文本和图标?

如何在 Flutter 中使用 Provider 显示来自 ChangeNotifier 的错误

Sliver 应用栏无法正确显示 - Flutter

如何在 Flutter 中弹出时清除页面

如何使用 Google Maps Flutter 默认显示地图标签

Flutter/Dart - 文本值未正确显示