【问题标题】:How to display SnackBar in Flutter?如何在 Flutter 中显示 SnackBar?
【发布时间】: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('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]),
          ),
        );
      },
    ) ;

  }
}

但是我的 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()。

标签: flutter widget snackbar


【解决方案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。 但是您可以自行检查并查看最适合您的。

      【讨论】:

        猜你喜欢
        • 2019-08-28
        • 2017-03-27
        • 2019-05-24
        • 2019-07-27
        • 1970-01-01
        • 1970-01-01
        • 2019-12-15
        • 2021-01-19
        • 2021-03-15
        相关资源
        最近更新 更多