如何在 Flutter 中正确显示 Snackbar?
How to properly display a Snackbar in Flutter?
我试图在点击 floatingActionbutton
时显示 Snackbar
。但是当我点击 floatingactionbutton
时,它没有显示任何内容。这是我的代码。我正在使用 StatefulWidget
。我调试并检查了 onPressed 函数也正在执行,但不知何故 Snackbar
不可见。问题的根本原因是什么?我觉得我传递的 BuildContext 有问题。
class MyApp extends StatefulWidget{
@override
MyAppState createState() {
// TODO: implement createState
return new MyAppState();
}
}
class MyAppState extends State<MyApp>{
File _image;
String _text;
Future getImage() async {
var image = await ImagePicker.pickImage(source: ImageSource.camera);
_image = image;
final FirebaseVisionImage visionImage = FirebaseVisionImage.fromFile(_image);
final TextRecognizer textRecognizer = FirebaseVision.instance.textRecognizer();
final VisionText visionText = await textRecognizer.processImage(visionImage);
String detectedText = visionText.text;
setState(() {
_image = image;
_text = detectedText;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: new AppBar(
title: new Text('Image Picker Example'),
),
body: new Center(
child: _image == null
? new Text('No image selected.')
: new Image.file(_image),
),
floatingActionButton: new FloatingActionButton(
onPressed: (){
showSnackBar(context);
// getImage();
},
tooltip: 'Pick Image',
child: new Icon(Icons.add_a_photo),
),
),
);
}
void showSnackBar(BuildContext context) {
final scaffold = Scaffold.of(context);
final snackBarContent = SnackBar(
content: Text("sagar"),
action: SnackBarAction(
label: 'UNDO', onPressed: scaffold.hideCurrentSnackBar),
);
scaffold.showSnackBar(snackBarContent);
}
}
class MyApp extends StatefulWidget{
@override
MyAppState createState() {
// TODO: implement createState
return new MyAppState();
}
}
class MyAppState extends State<MyApp>{
final GlobalKey<ScaffoldState> _scaffoldkey = new GlobalKey<ScaffoldState>();
File _image;
String _text;
Future getImage() async {
var image = await ImagePicker.pickImage(source: ImageSource.camera);
_image = image;
final FirebaseVisionImage visionImage = FirebaseVisionImage.fromFile(_image);
final TextRecognizer textRecognizer = FirebaseVision.instance.textRecognizer();
final VisionText visionText = await textRecognizer.processImage(visionImage);
String detectedText = visionText.text;
setState(() {
_image = image;
_text = detectedText;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
key: _scaffoldkey,
appBar: new AppBar(
title: new Text('Image Picker Example'),
),
body: new Center(
child: _image == null
? new Text('No image selected.')
: new Image.file(_image),
),
floatingActionButton: new FloatingActionButton(
onPressed: (){
showSnackBar();
// getImage();
},
tooltip: 'Pick Image',
child: new Icon(Icons.add_a_photo),
),
),
);
}
void showSnackBar() {
final snackBarContent = SnackBar(
content: Text("sagar"),
action: SnackBarAction(
label: 'UNDO', onPressed: _scaffoldkey.currentState.hideCurrentSnackBar),
);
_scaffoldkey.currentState.showSnackBar(snackBarContent);
}
}
发生这种情况是因为使用的 BuildContext
没有 Scaffold
祖先,因此将无法找到它来呈现 SnackBar
因为它取决于 Scaffold
来显示它。
根据 of method 文档:
When the Scaffold is actually created in the same build function, the
context argument to the build function can't be used to find the
Scaffold (since it's "above" the widget being returned). In such
cases, the following technique with a Builder can be used to provide a
new scope with a BuildContext that is "under" the Scaffold:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Demo')
),
body: Builder(
// Create an inner BuildContext so that the onPressed methods
// can refer to the Scaffold with Scaffold.of().
builder: (BuildContext context) {
return Center(
child: RaisedButton(
child: Text('SHOW A SNACKBAR'),
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('Hello!'),
));
},
),
);
},
),
);
}
解决方案
将您的 FloatingActionButton
包装在 Builder
小部件中比使用 GlobalKey
更优雅,这在 @Epizon 的回答中已经提到。
显示SnackBar你可以这样使用:
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('User Logged In'),
));
之前的SnackBar是这样使用的:
Scaffold.of(context).showSnackBar(SnackBar(
content: Text('Rahul Kushwaha!'),
));
现在,SnackBar 由ScaffoldMessenger管理。有关详细信息,请研究此 link
我在尝试从父级 Parent() => childLevel1 => childOfLevel1(){showing the snackbar here}
的二级子级 StatfulWidget
中 showSnackbar()
时遇到了这个问题
我实现了@Epizon 的回答,但是 .currentState.showSnackBar(snackBarContent);
被弃用了,据 flutter 说:
The SnackBar API within the Scaffold is now handled by the ScaffoldMessenger
read full document
所以在@Epizon 的回答中替换这一行:
_scaffoldKey.currentState!.showSnackBar(_snackBarContent);
对此:
ScaffoldMessenger.of(_scaffoldKey.currentState!.context) .showSnackBar(_snackBarContent);
将解决弃用问题
这是代码
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
void _showSnack(String msg) {
final _snackBarContent = SnackBar(content: Text(msg));
ScaffoldMessenger.of(_scaffoldKey.currentState!.context)
.showSnackBar(_snackBarContent);
}
return MaterialApp(
home: Scaffold(
//resizeToAvoidBottomInset: true,
key: _scaffoldKey,
body: Center(
child: ElevatedButton(
child: Text("show snackbar"),
onPressed(){_showSnack("im located in the btn's onPressed");},
);
);
我试图在点击 floatingActionbutton
时显示 Snackbar
。但是当我点击 floatingactionbutton
时,它没有显示任何内容。这是我的代码。我正在使用 StatefulWidget
。我调试并检查了 onPressed 函数也正在执行,但不知何故 Snackbar
不可见。问题的根本原因是什么?我觉得我传递的 BuildContext 有问题。
class MyApp extends StatefulWidget{
@override
MyAppState createState() {
// TODO: implement createState
return new MyAppState();
}
}
class MyAppState extends State<MyApp>{
File _image;
String _text;
Future getImage() async {
var image = await ImagePicker.pickImage(source: ImageSource.camera);
_image = image;
final FirebaseVisionImage visionImage = FirebaseVisionImage.fromFile(_image);
final TextRecognizer textRecognizer = FirebaseVision.instance.textRecognizer();
final VisionText visionText = await textRecognizer.processImage(visionImage);
String detectedText = visionText.text;
setState(() {
_image = image;
_text = detectedText;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: new AppBar(
title: new Text('Image Picker Example'),
),
body: new Center(
child: _image == null
? new Text('No image selected.')
: new Image.file(_image),
),
floatingActionButton: new FloatingActionButton(
onPressed: (){
showSnackBar(context);
// getImage();
},
tooltip: 'Pick Image',
child: new Icon(Icons.add_a_photo),
),
),
);
}
void showSnackBar(BuildContext context) {
final scaffold = Scaffold.of(context);
final snackBarContent = SnackBar(
content: Text("sagar"),
action: SnackBarAction(
label: 'UNDO', onPressed: scaffold.hideCurrentSnackBar),
);
scaffold.showSnackBar(snackBarContent);
}
}
class MyApp extends StatefulWidget{
@override
MyAppState createState() {
// TODO: implement createState
return new MyAppState();
}
}
class MyAppState extends State<MyApp>{
final GlobalKey<ScaffoldState> _scaffoldkey = new GlobalKey<ScaffoldState>();
File _image;
String _text;
Future getImage() async {
var image = await ImagePicker.pickImage(source: ImageSource.camera);
_image = image;
final FirebaseVisionImage visionImage = FirebaseVisionImage.fromFile(_image);
final TextRecognizer textRecognizer = FirebaseVision.instance.textRecognizer();
final VisionText visionText = await textRecognizer.processImage(visionImage);
String detectedText = visionText.text;
setState(() {
_image = image;
_text = detectedText;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
key: _scaffoldkey,
appBar: new AppBar(
title: new Text('Image Picker Example'),
),
body: new Center(
child: _image == null
? new Text('No image selected.')
: new Image.file(_image),
),
floatingActionButton: new FloatingActionButton(
onPressed: (){
showSnackBar();
// getImage();
},
tooltip: 'Pick Image',
child: new Icon(Icons.add_a_photo),
),
),
);
}
void showSnackBar() {
final snackBarContent = SnackBar(
content: Text("sagar"),
action: SnackBarAction(
label: 'UNDO', onPressed: _scaffoldkey.currentState.hideCurrentSnackBar),
);
_scaffoldkey.currentState.showSnackBar(snackBarContent);
}
}
发生这种情况是因为使用的 BuildContext
没有 Scaffold
祖先,因此将无法找到它来呈现 SnackBar
因为它取决于 Scaffold
来显示它。
根据 of method 文档:
When the Scaffold is actually created in the same build function, the context argument to the build function can't be used to find the Scaffold (since it's "above" the widget being returned). In such cases, the following technique with a Builder can be used to provide a new scope with a BuildContext that is "under" the Scaffold:
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Demo') ), body: Builder( // Create an inner BuildContext so that the onPressed methods // can refer to the Scaffold with Scaffold.of(). builder: (BuildContext context) { return Center( child: RaisedButton( child: Text('SHOW A SNACKBAR'), onPressed: () { ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text('Hello!'), )); }, ), ); }, ), ); }
解决方案
将您的 FloatingActionButton
包装在 Builder
小部件中比使用 GlobalKey
更优雅,这在 @Epizon 的回答中已经提到。
显示SnackBar你可以这样使用:
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('User Logged In'),
));
之前的SnackBar是这样使用的:
Scaffold.of(context).showSnackBar(SnackBar(
content: Text('Rahul Kushwaha!'),
));
现在,SnackBar 由ScaffoldMessenger管理。有关详细信息,请研究此 link
我在尝试从父级 Parent() => childLevel1 => childOfLevel1(){showing the snackbar here}
StatfulWidget
中 showSnackbar()
时遇到了这个问题
我实现了@Epizon 的回答,但是 .currentState.showSnackBar(snackBarContent);
被弃用了,据 flutter 说:
The SnackBar API within the Scaffold is now handled by the ScaffoldMessenger read full document
所以在@Epizon 的回答中替换这一行:
_scaffoldKey.currentState!.showSnackBar(_snackBarContent);
对此:
ScaffoldMessenger.of(_scaffoldKey.currentState!.context) .showSnackBar(_snackBarContent);
将解决弃用问题
这是代码
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
void _showSnack(String msg) {
final _snackBarContent = SnackBar(content: Text(msg));
ScaffoldMessenger.of(_scaffoldKey.currentState!.context)
.showSnackBar(_snackBarContent);
}
return MaterialApp(
home: Scaffold(
//resizeToAvoidBottomInset: true,
key: _scaffoldKey,
body: Center(
child: ElevatedButton(
child: Text("show snackbar"),
onPressed(){_showSnack("im located in the btn's onPressed");},
);
);