我的应用程序由树的根目录下的StatefulWidget
组成,它通过其状态以及回调以将状态更改为InheritedWidget
。在其中一个回调中,创建Firebase的Firestore内的文档的监听器以监听更改,然后显示SnackBar
通知用户该更改。
现在的问题是如何从树根处的父级访问当前活动的Scaffold
。在根目录和当前活动的Scaffold
之间可能有多个其他Scaffolds
,具体取决于推送到Navigator
的路由数量。但要显示SnackBar
,必须使用最新版本。
答案 0 :(得分:1)
我目前的解决方案可以在以下代码示例中找到。它有效,但我对所有想法都持开放态度。我目前不喜欢这个解决方案的是我需要调用回调来从GlobalKey
内推送当前didChangeDependencies
,因此引入一个成员变量以确保在生命周期中只调用一次。 Widget
,因为无法从InheritedWidget
访问initState
。
是否有人可以选择引入成员变量?
class MyApp extends StatefulWidget {
final Firestore firestore;
const MyApp(this.firestore);
@override
State<StatefulWidget> createState() {
return new MyAppState();
}
}
class MyAppState extends State<MyApp> {
void addDocumentListener(DocumentReference ref) {
ref.snapshots.listen((snapshot) {
_scaffoldKeys.last.currentState.showSnackBar(new SnackBar(content: new Text("Test")));
});
}
var _scaffoldKeys = new Queue<GlobalKey<ScaffoldState>>();
void pushScaffoldKey(GlobalKey<ScaffoldState> key) {
_scaffoldKeys.addLast(key);
}
GlobalKey<ScaffoldState> popScaffoldKey() {
return _scaffoldKeys.removeLast();
}
@override
Widget build(BuildContext context) {
return new MyInheritedWidget(addDocumentListener, pushScaffoldKey, popScaffoldKey, new MaterialApp(home: new HomePage()));
}
}
typedef VoidDocumentReferenceCallback(DocumentReference ref);
typedef VoidGlobalKeyScaffoldStateCallback(GlobalKey<ScaffoldState> key);
typedef GlobalKey<ScaffoldState> GlobalKeyScaffoldStateCallback();
class MyInheritedWidget extends InheritedWidget {
final VoidDocumentReferenceCallback addDocumentListener;
final VoidGlobalKeyScaffoldStateCallback pushScaffoldKey;
final GlobalKeyScaffoldStateCallback popScaffoldKey;
const MyInheritedWidget(this.addDocumentListener, this.pushScaffoldKey, this.popScaffoldKey, Widget child) : super(child: child);
@override
bool updateShouldNotify(InheritedWidget oldWidget) {
return false;
}
static MyInheritedWidget of(BuildContext context) {
return context.inheritFromWidgetOfExactType(MyInheritedWidget);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new CustomScaffold(
appBar: new AppBar(
title: new Text("Home Page"),
actions: <Widget>[
new IconButton(icon: const Icon(Icons.settings), onPressed: () {
Navigator.of(context).push(new MaterialPageRoute(builder: (context) {
// go to another page with a CustomScaffold
}));
})
],
),
body: new Center(
child: new RaisedButton(onPressed: () {
MyInheritedWidget.of(context).addDocumentListener(ref);
}, child: new Text("add listener")),
),
);
}
}
class CustomScaffold extends StatefulWidget {
final AppBar appBar;
final Widget body;
const CustomScaffold({this.appBar, this.body});
@override
State<StatefulWidget> createState() {
return new CustomScaffoldState();
}
}
class CustomScaffoldState extends State<CustomScaffold> {
final _key = new GlobalKey<ScaffoldState>();
bool _keyInitialized = false;
@override
didChangeDependencies() {
if (!_keyInitialized) {
MyInheritedWidget.of(context).pushScaffoldKey(_key);
_keyInitialized = true;
}
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
var scaffold = new Scaffold(
key: _key,
appBar: widget.appBar,
body: widget.body,
);
return new WillPopScope(child: scaffold, onWillPop: () {
MyInheritedWidget.of(context).popScaffoldKey();
return new Future.value(true);
});
}
}