在Flutter中显示SnackBar

问题描述 投票:0回答:20

我想在 Flutter 的 Stateful 小部件中显示一个

simple 
SnackBar。我的应用程序使用名为
MaterialApp
的有状态小部件创建
MyHomePage
的新实例。

我尝试在 showSnackBar() 方法中显示

SnackBar
。但它失败了
The method showSnackBar was called on 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)
    ));
  }
}

解决方案:

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)
    ));
  }
}
dart android-snackbar snackbar flutter
20个回答
76
投票

就我而言,我有这样的代码(在类状态)

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

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

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

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

小吃店开始工作:)


54
投票

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

最简单的解决方案是将 MyApp 小部件中的

home
行更改为:

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

...然后删除所有提及

_scaffoldKey
的内容,并在当前有
Scaffold.of(context)
的地方使用
_scaffoldKey.currentState


41
投票

ScaffoldState
现已弃用。使用
ScaffoldMessengerState

使用

SnackBar
显示
ScaffoldMessenger
通常有两种方法。


  1. 直接方式:

    @override
    Widget build(BuildContext context) {
      return Scaffold(
        body: ElevatedButton(
          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: ElevatedButton(
              onPressed: () {
                var snackBar = SnackBar(content: Text('Hello World'));
                _globalKey.currentState.showSnackBar(snackBar);
              },
              child: Text('Show SnackBar'),
            ),
          ),
        ),
      );
    }
    

33
投票

有一种更好、更干净的方式在 flutter 中显示 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 后代的上下文,而不是包含 Scaffold 的上下文。为了避免错误,我们需要为 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。例如,我用它来显示互联网连接消息。


14
投票

你可以使用这个:

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

11
投票
Scaffold.of(context).showSnackBar(
     SnackBar(content: Text("Thanks for using snackbar",
     textAlign: TextAlign.center, style: TextStyle(fontSize: 16.0, fontWeight: 
     FontWeight.bold),), duration: Duration(seconds: 2), backgroundColor: Colors.red,)
);

10
投票

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

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

7
投票

initState
之前被调用过
build
我猜
_scaffoldKey.currentState
在调用时还没有被初始化。

我不知道你是否可以从

ScaffoldState
得到一个
initState
。如果您更改代码,您可以通过
build
方法显示小吃栏:

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

6
投票

Scaffold.Of(context)
已弃用,用于显示小吃栏。

使用新方式:

final snackBar = SnackBar(content: Text('Yay! A SnackBar!'));

ScaffoldMessenger.of(context).showSnackBar(snackBar);

snackbars


4
投票

万一有人想要在

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

4
投票

您只需三个简单的步骤即可完成此操作。

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

    final _scaffoldKey = GlobalKey<ScaffoldState>();
    

2.现在您必须在脚手架中提及此键,方法是在脚手架中写入以下行:

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

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

4
投票

ScaffoldState 现已弃用。使用 ScaffoldMessengerState。

上述所有解决方案都很棒,但由于它现在已弃用,您应该以这种方式使用它。

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

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

3
投票

我们可以这样使用

**

ScaffoldMessenger.of(context).showSnackBar(
                        SnackBar(
                          content: Text("Enter your phone number"),
                        ),
                      );

**


2
投票

在Flutter中显示SnackBar

 ScaffoldMessenger.of(context).showSnackBar(SnackBar(
                                  content: Text('Please Enter Valid Data'),
                                  backgroundColor: Colors.red,
                                ));

示例:

 if(value.isNotEmpty && value != null){
 ScaffoldMessenger.of(context).showSnackBar(SnackBar(
                                  content: Text('Validated Successfully'),
                                  backgroundColor: Colors.green,
                                ));
}else{
 ScaffoldMessenger.of(context).showSnackBar(SnackBar(
                                  content: Text('Please Enter Valid Data'),
                                  backgroundColor: Colors.red,
                                ));
}

1
投票

最好的方法是创建一个 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


1
投票

如果您所在的小部件不直接具有

return Scaffold(...)
小部件,您可以执行以下操作:

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

无需创建额外的 Scaffold 小部件,因为

showSnackBar()
方法需要一个,您可以重复使用。


0
投票

零安全版本中--

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"),
                    )
                )
            )
        )
    );
  }
}

0
投票

使用此包装小吃店

自定义小吃栏:^0.0.1

showCustomSnackBar("你好", 10.0 ,5, Colors.white);


0
投票
ScaffoldMessenger.of(context)
                      .showSnackBar(new SnackBar(content: Text('SnackBar Message')));

  

0
投票
onPressed: () {
              ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: "pressed".text.make(),
              ));
            },
© www.soinside.com 2019 - 2024. All rights reserved.