在Flutter中显示SnackBar

时间:2016-11-13 23:15:46

标签: dart android-snackbar snackbar flutter

我想在Flutter 的有状态小部件中显示一个简单的SnackBar。我的应用程序使用名为 MyHomePage 的有状态窗口小部件创建 MaterialApp 的新实例。

我尝试在showSnackBar()方法中显示SnackBar。但它失败了'方法'showSnackBar'被调用为null '。

这段代码出了什么问题?

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key}) : super(key: key);

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

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

  @override
  void initState() {
    super.initState();
    showInSnackBar("Some text");
  }

  @override
  Widget build(BuildContext context) {
    return new Padding(
            key: _scaffoldKey,
            padding: const EdgeInsets.all(16.0),
            child: new Text("Simple Text")
    );
  }

  void showInSnackBar(String value) {
    _scaffoldKey.currentState.showSnackBar(new SnackBar(
        content: new Text(value)
    ));
  }
}

SOLUTION:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
        title: 'Flutter',
        theme: new ThemeData(
            primarySwatch: Colors.blue,
        ),
        home: new Scaffold(body: new MyHomePage()),
      );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key}) : super(key: key);

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    showInSnackBar("Some text");
    return new Padding(
        padding: const EdgeInsets.all(16.0),
        child: new Scaffold(
          body: new Text("Simple Text")
        )
    );
  }

  void showInSnackBar(String value) {
    Scaffold.of(context).showSnackBar(new SnackBar(
        content: new Text(value)
    ));
  }
}

16 个答案:

答案 0 :(得分:27)

有三个问题。首先,您不会在任何地方拥有脚手架,而脚手架小部件则是知道如何显示小吃店的小部件。第二个是你有一把钥匙可以抓住脚手架,但是你已经把它放在Padding上了(Paddings不知道小吃店)。第三个是你在与它关联的小部件之前使用了密钥有机会被初始化,因为在构建之前调用了initState。

最简单的解决方案是将MyApp小部件中的home行更改为:

home: new Scaffold(body: new MyHomePage()),

...然后删除所有提及的_scaffoldKey,而使用Scaffold.of(context),而您当前拥有_scaffoldKey.currentState

答案 1 :(得分:10)

在我的情况下,我有这样的代码(在类州)

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

void showInSnackBar(String value) {
    _scaffoldKey.currentState.showSnackBar(new SnackBar(content: new Text(value)));
}

但我没有设置脚手架的钥匙。 所以当我添加键:_scaffoldKey

 @override
 Widget build(BuildContext context) {
  return new Scaffold(
    key: _scaffoldKey,
    body: new SafeArea(

snackbar开始工作:)

答案 2 :(得分:8)

有一种更好更清洁的方式来显示颤动的Snackbar。我发现它很难分享,所以也许对其他人有帮助。

无需更改主应用部分

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
  return new MaterialApp(
    title: 'MyApp',
    theme: new ThemeData(
    primarySwatch: Colors.orange),
    home: new MainPage());
  }
}

页面状态代码是事物发生变化的地方。

我们知道Flutter提供Scaffold.of(context).showSnackBar。但是,上下文应该是脚手架后代的上下文,而不是包含脚手架的上下文。为了避免错误,我们需要为Scaffold的主体使用BuildContext,并将其存储在变量中,如下所示。

class MainPageState extends State<MainPage> {                                                                         
BuildContext scaffoldContext;                                                                                                                                                                                                

@override                                                                                                           
Widget build(BuildContext context) {                                                                                

return new Scaffold(                                                                                              
    backgroundColor: Colors.grey,                                                                                 
    appBar: new AppBar(                                                                                           
      title: const Text(APP_TITLE),                                                                               
    ),                                                                                                             
    body: new Builder(builder: (BuildContext context) {                                                           
      scaffoldContext = context;                                                                                  
      return new Center(
           child: new Text('Hello World', style: new TextStyle(fontSize: 32.0)),
         );                                                                                
    }));                                                                                                           
}                                                                                                                   


void createSnackBar(String message) {                                                                               
  final snackBar = new SnackBar(content: new Text(message),                                                         
  backgroundColor: Colors.red);                                                                                      

  // Find the Scaffold in the Widget tree and use it to show a SnackBar!                                            
  Scaffold.of(scaffoldContext).showSnackBar(snackBar);                                                              
  }                                                                                                                   
}     

现在,您可以从任何地方调用此函数,它将显示Snackbar。例如,我用它来显示Internet连接消息。

答案 3 :(得分:4)

ScaffoldState现在已弃用。使用ScaffoldMessengerState

通常有两种使用SnackBar显示ScaffoldMessenger的方式。


  1. 直接方法:

    @override
    Widget build(BuildContext context) {
      return Scaffold(
        body: RaisedButton(
          onPressed: () {
            var snackBar = SnackBar(content: Text('Hello World'));
            ScaffoldMessenger.of(context).showSnackBar(snackBar);
          },
          child: Text('Show SnackBar'),
        ),
      );
    }
    

  1. 使用GlobalKey

    final _globalKey = GlobalKey<ScaffoldMessengerState>();
    
    @override
    Widget build(BuildContext context) {
      return ScaffoldMessenger(
        key: _globalKey,
        child: Scaffold(
          body: Center(
            child: RaisedButton(
              onPressed: () {
                var snackBar = SnackBar(content: Text('Hello World'));
                _globalKey.currentState.showSnackBar(snackBar);
              },
              child: Text('Show SnackBar'),
            ),
          ),
        ),
      );
    }
    

答案 4 :(得分:3)

initState之前调用了{p> build我猜_scaffoldKey.currentState在调用时尚未初始化。

我不知道你是否可以从ScaffoldState获得initState。如果您更改了代码,则可以使用build方法显示小吃栏:

Scaffold.of(context).showSnackBar(new SnackBar(new Text(value)));

答案 5 :(得分:2)

万一有人想在Snackbar上初始化initState()(换句话说,当页面加载在这里是我的解决方案)。另外,我假设您已经安装了_scaffoldKey

void initState() {
  super.initState();
  Future.delayed(Duration(seconds: 1)).then(
    (_) => _displaySnackbar
  );
}

// Display Snackbar
void get _displaySnackbar {
  _scaffoldKey.currentState.showSnackBar(SnackBar(
    duration: Duration(minutes: 1),
    content: Text('Your snackbar message')
  ));
}

答案 6 :(得分:2)

您可以使用:

final _scaffoldKey = GlobalKey<ScaffoldState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: _scaffoldKey,
      appBar: AppBar(


    ),
  }
}

然后 在onPressed()中可以添加此代码

_scaffoldKey.currentState.showSnackBar(
       new SnackBar(
          content: new Text('Hello this is snackbar!')
       )
);

答案 7 :(得分:2)

您可以通过三个简单的步骤来完成此操作。

  1. 确保您具有脚手架钥匙。您可以通过编写以下代码来创建该代码:

    final _scaffoldKey = GlobalKey<ScaffoldState>();
    

2。现在,您必须在脚手架中提及此密钥,方法是在脚手架内编写以下行:

key:_scaffoldKey,
  1. 现在您可以通过显示以下内容显示小吃店:

    final snackBar=SnackBar(
                          content: Text('Your password has been changed successfully'),
                        );
                        _scaffoldKey.currentState.showSnackBar(snackBar);
    

答案 8 :(得分:2)

Scaffold.Of(context) 已弃用以显示小吃店。

使用新方法:

somefunction

https://flutter.dev/docs/cookbook/design/snackbars

答案 9 :(得分:1)

我喜欢它,为我工作:)

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

答案 10 :(得分:1)

要在initState()上初始化Snackbar,可以在构建布局后执行一个函数。

void initState() {
super.initState();
WidgetsBinding.instance
    .addPostFrameCallback((_) => _scaffoldKey.currentState.showSnackBar(SnackBar(content: Text("Your message here..")));}

答案 11 :(得分:1)

**

ScaffoldState现在已弃用。使用ScaffoldMessengerState。

**

以上所有解决方案都很了不起,但由于现在已过时,您应该以这种方式使用它。

    var snackBar = SnackBar(content: Text('Hello World'));

    ScaffoldMessenger.of(_scaffoldKey.currentContext)
    .showSnackBar(snackBar );

答案 12 :(得分:0)

{% url %}

答案 13 :(得分:0)

打开小吃店有很多方法,但是我要说的是,有一种无需任何上下文即可打开小吃店并完全自定义它的方法,它可以使用颜色,模糊,形状,渐变,图标以及从字面上进行的任何操作通过此程序包:

https://pub.dev/packages/get

代替传递上下文,而不是创建globalKey并将其附加到您的Scaffold上,您只需调用:Get.snackbar("Hi", "your message");并准备好! 最有趣的是,您可以从任何地方调用小吃栏,例如,当API发生故障时,可以从控制器返回错误消息。 这是非常值得知道的。

答案 14 :(得分:0)

最好的方法是创建一个PageWrapper,您可以包装所有页面以获取Scaffold小部件的上下文,并避免再次遇到这些错误。

以下是页面包装程序的示例:

import 'package:flutter/material.dart';

class PageWrapper extends StatelessWidget {

  Widget page;

  WPage(this.page);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      body: page
    );
  }
}

然后,您可以将所有页面包装在main.dart中,如下所示:

import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(
  initialRoute: '/login',
  routes: {
    '/login': (context) => PageWrapper(Login()),
    '/home': (context) => PageWrapper(Home())
  }
));

现在,您可以在任意页面的任何地方调用Scaffold.of(context)

参考:https://noobieprogrammer.blogspot.com/2020/06/how-to-create-error-alert-or-popup.html

或观看视频版本(长5分钟):https://youtu.be/u9KoFtu0HEY

答案 15 :(得分:0)

如果您位于没有直接return Scaffold(...)小部件的小部件中,则可以执行以下操作:

Scaffold.of(context).showSnackBar(SnackBar(content: Text("Hello from snackbar")));

无需创建额外的Scaffold小部件,因为showSnackBar()方法需要一个,即可重复使用。