如何在 Flutter 中显示 SnackBar?

Posted

技术标签:

【中文标题】如何在 Flutter 中显示 SnackBar?【英文标题】:How to display SnackBar in Flutter? 【发布时间】:2020-09-24 10:28:02 【问题描述】:

我想在我的 Flutter 应用中显示一个 SnackBar。我已经阅读了文档并复制了它: 我的脚手架主体:

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

SnackBarPage 类:

class SnackBarPage extends StatelessWidget 

  void jelszopress(TextEditingController jelszoController, BuildContext context) async
    var jelszo;
    DocumentReference docRef =   
    Firestore.instance.collection('clas-s-rooms').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]),
          ),
        );
      ,
    ) ;

  

但是我的 cody 没有显示 SnackBar。我尝试了这个问题的解决方案:How to properly display a Snackbar in Flutter? 但添加 Builder 小部件并没有帮助。

【问题讨论】:

控制台是否有任何错误? SnackBar 必须在 Scaffold Widget 中。我们可以使用 SnackBarPage() 看到父小部件 @Danaru 我已经编辑了帖子。 @MohammadAssadArshad 我明白了:[ERROR:flutter/lib/ui/ui_dart_state.cc(157)] 未处理的异常:使用不包含 Scaffold 的上下文调用 Scaffold.of()。 【参考方案1】:

"Scaffold.of(context)" 已被弃用,将返回 null。现在使用 "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'),
        ),
      ),
    );
  

注意:确保您的 main.dart 覆盖的 build() 函数应将 "MaterialApp" 作为小部件返回,例如:

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

【讨论】:

【参考方案2】:

因此,根据错误,Snackbar.of() 中传递的上下文似乎不是正确的上下文。这基于1 & 2 是有意义的;和摘要复制如下:

每个小部件都有自己的 BuildContext,它成为 StatelessWidget.build 或 State.build 函数返回的小部件的父级。 (同样,RenderObjectWidgets 的任何子级的父级。)

特别是,这意味着在构建方法中,构建方法的小部件的构建上下文与该构建方法返回的小部件的构建上下文不同。

所以这意味着您在jelszoba(context) 函数中传递的构建上下文不是您需要的构建上下文,实际上是实例化 Scaffold 的小部件的构建上下文。

那么如何解决: 要解决此问题,请将您的 Card 小部件包装在 Builder 小部件中的 SnackbarPage 中,并将其中的上下文传递给 jelszoba(context) 方法。

一个来自1的例子我贴在下面:

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

【讨论】:

【参考方案3】:

您通常可以通过这种方式在底部导航栏中使用小吃栏。但是,如果你想在正文中显示它,那么只需从 Builder 中复制代码并将其粘贴到脚手架的正文中即可。

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

注意:在 SnackBar 的行为属性中,您可以将其留空。但问题在于“如果您有弯曲导航栏或底部导航栏上方有一个浮动操作按钮,那么小吃栏将提升这些图标(或 FAB )并影响 UI”。这就是为什么 SnackBar.floating 更受青睐的原因,因为它更适合 UI。 但是您可以自行检查并查看最适合您的。

【讨论】:

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

Flutter - 如何在“Future”中显示“snackbar”

在 Flutter 中打开应用程序时如何显示 Snackbar 或底部工作表?

如何在 Flutter 中延迟 SnackBar

如何在顶部显示 Flutter SnackBar 小部件?

Flutter:导航离开时如何关闭 SnackBar?

Flutter:调用 setState() 方法后不显示 SnackBar