我正在尝试跟踪当前的Scaffold(它们的BuildContext),以创建一个应用程序范围的SnackBar函数。当前,我正在创建一个class,它显示一个Scaffold并将其context添加到另一个class,后者管理当前正在运行的Scaffold。但是,我没有成功,因为我目前的尝试有两个问题:

  • 不能正确存储当前Scaffold
  • 显然,对于从当前disposeScaffoldBuildContext中删除ListScaffold而言,BuildContext方法为时已晚,因此向我展示了Exception,“Looking up a deactivated widget's ancestor is unsafe.

  • 这是我目前的尝试:
  • 实现(main.dart):
  • import 'package:flutter/foundation.dart';
    import 'package:flutter/material.dart';
    
    import 'MScaffold.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Snackbar manager',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: MyHomePage(title: 'Snackbar manager'),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key key, this.title}) : super(key: key);
      final String title;
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      @override
      Widget build(BuildContext context) {
        return MScaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: Center(),
          floatingActionButton: Column(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              FloatingActionButton(
                heroTag: 0,
                child:Icon(Icons.add_circle_outline),
                onPressed: (){
                  MScaffoldManager.showSnackbar();
                },
              ),
              FloatingActionButton(
                heroTag: 1,
                child:Icon(Icons.remove_circle_outline),
                onPressed: (){
                  MScaffoldManager.hideSnackbar();
                },
              ),
              FloatingActionButton(
                heroTag: 2,
                child:Icon(Icons.add),
                onPressed: (){
                  Navigator.of(context).push(
                    MaterialPageRoute(
                      builder: (context){
                        return SecondScaffold();
                      }
                    )
                  );
                },
              ),
            ],
          ),
        );
      }
    }
    
    class SecondScaffold extends StatelessWidget{
      @override
      Widget build(BuildContext context){
        return MScaffold(
          appBar: AppBar(
            title: Text("Page 2"),
          ),
          body: Center(),
          floatingActionButton: Column(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              FloatingActionButton(
                heroTag: 0,
                child:Icon(Icons.add_circle_outline),
                onPressed: (){
                  MScaffoldManager.showSnackbar();
                },
              ),
              FloatingActionButton(
                heroTag: 1,
                child:Icon(Icons.remove_circle_outline),
                onPressed: (){
                  MScaffoldManager.hideSnackbar();
                },
              ),
              FloatingActionButton(
                heroTag: 2,
                child:Icon(Icons.remove),
                onPressed: (){
                  Navigator.of(context).pop();
                },
              ),
            ],
          ),
        );
      }
    }
    
  • library class es:MScaffoldManager; MScaffold;和MScaffoldState:
  • 
    import 'package:flutter/cupertino.dart';
    import 'package:flutter/gestures.dart';
    import 'package:flutter/material.dart';
    
    class MScaffoldManager{
      static List<Map> scaffoldInformation = List();
      static void addScaffold(context){
        scaffoldInformation.add({'context':context});
        print("Scaffold added:\n"+scaffoldInformation.toString());
      }
      static void removeScaffold(context){
        Scaffold.of(context).hideCurrentSnackBar();
        scaffoldInformation.remove({'context':context});
        print("Scaffold removed:\n"+scaffoldInformation.toString());
      }
      static void showSnackbar(){
        scaffoldInformation.forEach((v){
          Scaffold.of(v['context']).showSnackBar(SnackBar(
            content: Text("Snackbar works"),
          ));
        });
      }
      static void hideSnackbar(){
        scaffoldInformation.forEach((v){
          Scaffold.of(v['context']).hideCurrentSnackBar();
        });
      }
    }
    
    
    class MScaffold extends StatefulWidget{
      Key key;
      var appBar;
      var body;
      var floatingActionButton;
      var floatingActionButtonLocation;
      var floatingActionButtonAnimator;
      var persistentFooterButtons;
      var drawer;
      var endDrawer;
      var bottomNavigationBar;
      var bottomSheet;
      var backgroundColor;
      var resizeToAvoidBottomPadding;
      var resizeToAvoidBottomInset;
      var primary;
      var drawerDragStartBehavior;
      var extendBody;
      var extendBodyBehindAppBar;
      var drawerScrimColor;
      var drawerEdgeDragWidth;
    
      MScaffold({
        Key key,
        this.appBar,
        this.body,
        this.floatingActionButton,
        this.floatingActionButtonLocation,
        this.floatingActionButtonAnimator,
        this.persistentFooterButtons,
        this.drawer,
        this.endDrawer,
        this.bottomNavigationBar,
        this.bottomSheet,
        this.backgroundColor,
        this.resizeToAvoidBottomPadding,
        this.resizeToAvoidBottomInset,
        this.primary = true,
        this.drawerDragStartBehavior = DragStartBehavior.start,
        this.extendBody = false,
        this.extendBodyBehindAppBar = false,
        this.drawerScrimColor,
        this.drawerEdgeDragWidth,
      })  : assert(primary != null),
          assert(extendBody != null),
          assert(extendBodyBehindAppBar != null),
          assert(drawerDragStartBehavior != null);
    
      @override
      State<StatefulWidget> createState() {
        return MScaffoldState(
          key: key,
          appBar: appBar,
          body: body,
          floatingActionButton: floatingActionButton,
          floatingActionButtonLocation: floatingActionButtonLocation,
          floatingActionButtonAnimator: floatingActionButtonAnimator,
          persistentFooterButtons: persistentFooterButtons,
          drawer: drawer,
          endDrawer: endDrawer,
          bottomNavigationBar: bottomNavigationBar,
          bottomSheet: bottomSheet,
          backgroundColor: backgroundColor,
          resizeToAvoidBottomPadding: resizeToAvoidBottomPadding,
          resizeToAvoidBottomInset: resizeToAvoidBottomInset,
          primary: primary,
          drawerDragStartBehavior: drawerDragStartBehavior,
          extendBody: extendBody,
          extendBodyBehindAppBar: extendBodyBehindAppBar,
          drawerScrimColor: drawerScrimColor,
          drawerEdgeDragWidth: drawerEdgeDragWidth,
        );
      }
    
    }
    
    class MScaffoldState extends State<MScaffold> {
      Key key;
      var appBar;
      var body;
      var floatingActionButton;
      var floatingActionButtonLocation;
      var floatingActionButtonAnimator;
      var persistentFooterButtons;
      var drawer;
      var endDrawer;
      var bottomNavigationBar;
      var bottomSheet;
      var backgroundColor;
      var resizeToAvoidBottomPadding;
      var resizeToAvoidBottomInset;
      var primary;
      var drawerDragStartBehavior;
      var extendBody;
      var extendBodyBehindAppBar;
      var drawerScrimColor;
      var drawerEdgeDragWidth;
    
      MScaffoldState({
        Key key,
        this.appBar,
        this.body,
        this.floatingActionButton,
        this.floatingActionButtonLocation,
        this.floatingActionButtonAnimator,
        this.persistentFooterButtons,
        this.drawer,
        this.endDrawer,
        this.bottomNavigationBar,
        this.bottomSheet,
        this.backgroundColor,
        this.resizeToAvoidBottomPadding,
        this.resizeToAvoidBottomInset,
        this.primary = true,
        this.drawerDragStartBehavior = DragStartBehavior.start,
        this.extendBody = false,
        this.extendBodyBehindAppBar = false,
        this.drawerScrimColor,
        this.drawerEdgeDragWidth,
      })  : assert(primary != null),
          assert(extendBody != null),
          assert(extendBodyBehindAppBar != null),
          assert(drawerDragStartBehavior != null);
    
      @override
      void initState() {
        super.initState();
      }
      @override
      dispose(){
        MScaffoldManager.removeScaffold(_scaffoldContext);
        super.dispose();
    
      }
      BuildContext _scaffoldContext;
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          key: key,
          appBar: appBar,
          body: Builder(
            builder: (context){
              if(_scaffoldContext!=null)
                MScaffoldManager.removeScaffold(_scaffoldContext);
              _scaffoldContext = context;
              MScaffoldManager.addScaffold(_scaffoldContext);
              return body;
            },
          ),
          floatingActionButton: floatingActionButton,
          floatingActionButtonLocation: floatingActionButtonLocation,
          floatingActionButtonAnimator: floatingActionButtonAnimator,
          persistentFooterButtons: persistentFooterButtons,
          drawer: drawer,
          endDrawer: endDrawer,
          bottomNavigationBar: bottomNavigationBar,
          bottomSheet: bottomSheet,
          backgroundColor: backgroundColor,
          resizeToAvoidBottomPadding: resizeToAvoidBottomPadding,
          resizeToAvoidBottomInset: resizeToAvoidBottomInset,
          primary: primary,
          drawerDragStartBehavior: drawerDragStartBehavior,
          extendBody: extendBody,
          extendBodyBehindAppBar: extendBodyBehindAppBar,
          drawerScrimColor: drawerScrimColor,
          drawerEdgeDragWidth: drawerEdgeDragWidth,
        );
      }
    }
    

    承认它不能按原样工作,它似乎也有些冗长和困惑。我想做的就是简单地制作一个Scaffold class,其功能类似于Scaffold,但是与管理器class一起使用,它可以跟踪所有Scaffoldcontext,因此无论什么页面,我都可以轻松显示SnackBar消息用户开启。

    最佳答案

    我还没有亲自尝试过此代码,但是您如何创建要与ChangeNotifier一起使用的Provider并将其附加在MaterialApp上方:

    class MyErrorChangeNotifier extends ChangeNotifier {
      String error;
    
      setError(String error) {
        this.error = error;
    
        notifyListeners();
      }
    }
    

    然后创建一个自定义的Scaffold,如果已安装SnackBar,则每次调用setError时都会显示Scaffold:
    class MyScaffold extends Scaffold {
      // TODO constructor
    
      @override
      ScaffoldState createState() => MyScaffoldState();
    }
    
    class MyScaffoldState extends ScaffoldState {
      MyErrorChangeNotifier _myErrorCN;
      Function() _listener;
    
      @override
      void initState() {
        super.initState();
    
        _listener = () {
          if (mounted) {
            showSnackBar(SnackBar(content: Text(_myErrorCN.error)));
          }
        };
    
        Future.microtask(() {
          _myErrorCN = Provider.of<MyErrorChangeNotifier>(context, listen: false)..addListener(_listener);
        });
      }
    
      @override
      void dispose() {
        _myErrorCN?.removeListener(_listener);
    
        super.dispose();
      }
    }
    

    每当有这种使用案例时,请尝试使用提供程序考虑解决方案-将数据从上下文层次结构发送到ChangeNotifier,ChangeNotifier然后将数据从上下文层次结构发送回所有侦听它的小部件。

    10-08 03:05