可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I want to display a simple SnackBar inside Flutter's stateful widget. My application creates new instance of MaterialApp with a stateful widget called MyHomePage.
I try to show the SnackBar in showSnackBar() method. But it fails with 'The method 'showSnackBar' was called on null'.
What's wrong with this code?
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) )); } }
回答1:
There's three problems. The first is that you don't have a Scaffold anywhere, and the Scaffold widget is the one that knows how to show snack bars. The second is that you have a key for getting a hold of the scaffold, but you've put it on a Padding instead (and Paddings don't have any knowledge of snack bars). The third is that you've used the key before the widget that it's associated with has had a chance to be initialised, since initState is called before build.
The simplest solution is to change the home
line in your MyApp widget to:
home: new Scaffold(body: new MyHomePage()),
...and then remove all mention of _scaffoldKey
and instead use Scaffold.of(context)
where you currently have _scaffoldKey.currentState
.
回答2:
In my case i had code like this (in class state)
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>(); void showInSnackBar(String value) { _scaffoldKey.currentState.showSnackBar(new SnackBar(content: new Text(value))); }
but i didn't setup the key for scaffold. so when i add key: _scaffoldKey
@override Widget build(BuildContext context) { return new Scaffold( key: _scaffoldKey, body: new SafeArea(
snackbar start to work :)
回答3:
There's a better and cleaner way to display a Snackbar in flutter. I found it the hard way and sharing so that maybe it's helpful for someone else.
No need to change in your main app part
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return new MaterialApp( title: 'MyApp', theme: new ThemeData( primarySwatch: Colors.orange), home: new MainPage()); } }
Page State code is where things will change.
We know Flutter provides Scaffold.of(context).showSnackBar
. However, the context should be the context of a descendant of a Scaffold, and not the context that includes a Scaffold. In order to avoid error, we need to use a BuildContext for the body of the Scaffold, and store it in a variable, as below.
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); } }
Now, you can call this function from anywhere and it will display the Snackbar. For example, I am using it to display Internet Connectivity messages.
回答4:
initState
been called before build
I guess _scaffoldKey.currentState
has not been initialized when it is call.
I don't know if you can get a ScaffoldState
from initState
. If you change your code you can show the snackbar from build
method with:
Scaffold.of(context).showSnackBar(new SnackBar(new Text(value)));
回答5:
In case someone is looking to initialise a Snackbar
on initState()
(in other words when the page loads here is my solution). Also, I assume you already have the _scaffoldKey
in place.
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:
I dit it, work for me :)
@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!'), )); }, ), ); }, ), ); }