如何从根祖先访问Flutter中最新的脚手架?

时间:2018-04-22 15:37:54

标签: flutter

我的应用程序由树的根目录下的StatefulWidget组成,它通过其状态以及回调以将状态更改为InheritedWidget。在其中一个回调中,创建Firebase的Firestore内的文档的监听器以监听更改,然后显示SnackBar通知用户该更改。

现在的问题是如何从树根处的父级访问当前活动的Scaffold。在根目录和当前活动的Scaffold之间可能有多个其他Scaffolds,具体取决于推送到Navigator的路由数量。但要显示SnackBar,必须使用最新版本。

1 个答案:

答案 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);
    });
  }
}