如何在 Flutter 中正确显示 Snackbar?
Posted
技术标签:
【中文标题】如何在 Flutter 中正确显示 Snackbar?【英文标题】:How to properly display a Snackbar in Flutter? 【发布时间】:2019-05-24 03:01:18 【问题描述】:我试图在点击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);
【问题讨论】:
【参考方案1】:发生这种情况是因为使用的BuildContext
没有Scaffold
祖先,因此无法找到它来呈现SnackBar
,因为它取决于Scaffold
来显示它。
根据of method 文档:
当 Scaffold 实际在同一个构建函数中创建时, 构建函数的上下文参数不能用于查找 脚手架(因为它在被返回的小部件“上方”)。在这样的 在这种情况下,可以使用以下带有 Builder 的技术来提供 具有位于脚手架“下方”的 BuildContext 的新范围:
@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
小部件中将比使用 @Epizon 答案中已经提到的 GlobalKey
更优雅。
【讨论】:
【参考方案2】: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);
【讨论】:
【参考方案3】:显示SnackBar你可以这样使用:
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('User Logged In'),
));
以前的SnackBar是这样使用的:
Scaffold.of(context).showSnackBar(SnackBar(
content: Text('Rahul Kushwaha!'),
));
现在,SnackBar 由 ScaffoldMessenger 管理。有关详细信息,请研究此link
【讨论】:
【参考方案4】:在最新版本中--
完整示例
import 'package:flutter/material.dart';
void test()
runApp(MyApp());
class MyApp extends StatelessWidget
// This widget is the root of your application.
@override
Widget build(BuildContext context)
return MaterialApp(
title: 'Test App',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: testPage(title: 'Flutter Demo Home Page'),
);
class testPage extends StatefulWidget
testPage(Key? key, required this.title) : super(key: key);
final String title;
@override
_testPageState createState() => _testPageState();
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"),
)
)
)
)
);
[1]: https://i.stack.imgur.com/hKQYZ.jpg
【讨论】:
以上是关于如何在 Flutter 中正确显示 Snackbar?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Flutter 中使用 Provider 显示来自 ChangeNotifier 的错误