我有这个:
final GlobalKey<ScaffoldState> _scaffoldkey = new GlobalKey<ScaffoldState>();
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
key: _scaffoldkey,
drawer: Menu(),
appBar: AppBar(
title: Container(
child: Text('Dashboard'),
),
bottom: TabBar(
tabs: <Widget>[
...
],
),
),
body: TabBarView(
children: <Widget>[
...
],
),
),
);
}
}
现在,drawer: Menu()
从另一个menu.dart
文件导入,如下所示:
class Menu extends StatelessWidget {
final GlobalKey<ScaffoldState> drawerKey = new GlobalKey<ScaffoldState>();
@override
Widget build(BuildContext context) {
return new Drawer(
key: drawerKey,
child: new ListView(
children: <Widget>[
new ListTile(
dense: true,
title: new Text('My Text'),
onTap: () {
// On tap this, I want to show a snackbar.
scaffoldKey.currentState.showSnackBar(showSnack('Error. Could not log out'));
},
),
],
),
);
}
}
通过上述方法,我得到了
NoSuchMethodError: The method 'showSnackBar' was called on null.
一个简单的解决方案是将全部menu.dart
的内容直接塞入drawer: ...
中。
我正在查看的另一种方法是能够引用父支架以显示小吃栏。
如何做到这一点?
为什么甚至不能只在Flutter的任何地方打电话给快餐店,而必须通过脚手架来完成它?为什么?
答案 0 :(得分:7)
您应尽量避免使用GlobalKey
;使用Scaffold.of
获取ScaffoldState几乎总是更好。由于您的菜单位于小部件树中的支架下方,因此Scaffold.of(context)
会做您想要的事情。
您尝试执行的操作不起作用的原因是,您要创建两个单独的GlobalKey-每个都有自己的对象。将它们视为全局指针-由于您要创建两个不同的指针,因此它们指向不同的事物。而且状态实际上应该是分析失败,因为您将错误的类型传递到了抽屉的key
字段中。
如果由于某些原因绝对必须使用GlobalKeys,最好将外部小部件中创建的实例作为成员(即Menu
)传递到this.scaffoldKey
类中,但这不是推荐。
使用Scaffold.of
,这是您的代码在onTap函数中的样子:
onTap: () {
// On tap this, I want to show a snackbar.
Scaffold.of(context).showSnackBar(showSnack('Error. Could not log out'));
},
答案 1 :(得分:0)
您可以通过使用构建器小部件来实现此功能,而无需将单独的GlobalKey或传递密钥作为参数。只需将小部件包装到Builder小部件
class CustomDrawer extends StatelessWidget {@override Widget build(BuildContext context) {
return new Drawer(
child: new ListView(
children: <Widget>[
new Builder(builder: (BuildContext innerContext) {
return ListTile(
dense: true,
title: new Text('My Text'),
onTap: () {
Navigator.of(context).pop();
Scaffold.of(innerContext).showSnackBar(SnackBar(
content: Text('Added added into cart'),
duration: Duration(seconds: 2),
action: SnackBarAction(label: 'UNDO', onPressed: () {}),
));
}
);
})
],
),
);}}
答案 2 :(得分:0)
从你的第一个问题
要在菜单小部件中引用父脚手架,您可以将 _scaffoldkey
作为参数传递给菜单小部件,并使用 ScaffoldMessenger.of()
显示小吃栏,如下所示
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// Root Widget
@override
Widget build(BuildContext context) {
return MaterialApp(
// App name
title: 'Flutter SnackBar',
// Theme
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Test(title: 'SnackBar'),
);
}
}
class Test extends StatefulWidget {
final String? title;
final GlobalKey<ScaffoldState> _scaffoldkey = new GlobalKey<ScaffoldState>();
Test({@required this.title});
@override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
key: widget._scaffoldkey,
drawer: Menu(parentScaffoldkey:widget._scaffoldkey),
appBar: AppBar(
title: Container(
child: Text('Dashboard'),
),
bottom: TabBar(
tabs: <Widget>[
Tab(text:"Home"),
Tab(text:"About")
],
),
),
body: TabBarView(
children: <Widget>[
Text("Home"),
Text("About")
],
),
),
);
}
}
如图所示的菜单部分
class Menu extends StatelessWidget {
final parentScaffoldkey;
Menu({this.parentScaffoldkey});
@override
Widget build(BuildContext context) {
return new Drawer(
child: new ListView(
children: <Widget>[
new ListTile(
dense: true,
title: new Text('My Text'),
onTap: () {
// On tap show a snackbar.
// ScaffoldMessenger will call the nearest Scaffold to show snackbar
ScaffoldMessenger.of(this.parentScaffoldkey.currentContext).showSnackBar(SnackBar(content:Text('Error. Could not log out')));
},
),
],
),
);
}
}
此外,您必须通过 Scaffold 调用小吃店,因为它提供了 SnackBar API 并对其进行管理