Force Flutter navigator to reload state when popping

前端 未结 14 2070
情书的邮戳
情书的邮戳 2020-11-28 22:54

I have one StatefulWidget in Flutter with button, which navigates me to another StatefulWidget using Navigator.push(). On second widge

相关标签:
14条回答
  • 2020-11-28 23:25

    This work really good, i got from this doc from flutter page: flutter doc

    I defined the method to control navigation from first page.

    _navigateAndDisplaySelection(BuildContext context) async {
        final result = await Navigator.push(
          context,
          MaterialPageRoute(builder: (context) => AddDirectionPage()),
        );
    
        //below you can get your result and update the view with setState
        //changing the value if you want, i just wanted know if i have to  
        //update, and if is true, reload state
    
        if (result) {
          setState(() {});
        }
      }
    

    So, i call it in a action method from a inkwell, but can be called also from a button:

    onTap: () {
       _navigateAndDisplaySelection(context);
    },
    

    And finally in the second page, to return something (i returned a bool, you can return whatever you want):

    onTap: () {
      Navigator.pop(context, true);
    }
    
    0 讨论(0)
  • 2020-11-28 23:26

    There's a couple of things you could do here. @Mahi's answer while correct could be a little more succinct and actually use push rather than showDialog as the OP was asking about. This is an example that uses Navigator.push:

    import 'package:flutter/material.dart';
    
    class SecondPage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return new Container(
          color: Colors.green,
          child: new Column(
            children: <Widget>[
              new RaisedButton(
                onPressed: () => Navigator.pop(context),
                child: new Text("back"),
              ),
            ],
          ),
        );
      }
    }
    
    class FirstPage extends StatefulWidget {
      @override
      State<StatefulWidget> createState() => new FirstPageState();
    }
    
    class FirstPageState extends State<FirstPage> {
    
      Color color = Colors.white;
    
      @override
      Widget build(BuildContext context) {
        return new Container(
          color: color,
          child: new Column(
            children: <Widget>[
              new RaisedButton(
                  child: new Text("next"),
                  onPressed: () {
                    Navigator
                        .push(
                      context,
                      new MaterialPageRoute(builder: (context) => new SecondPage()),
                    )
                        .then((value) {
                      setState(() {
                        color = color == Colors.white ? Colors.grey : Colors.white;
                      });
                    });
                  }),
            ],
          ),
        );
      }
    }
    
    void main() => runApp(
          new MaterialApp(
            builder: (context, child) => new SafeArea(child: child),
            home: new FirstPage(),
          ),
        );
    

    However, there's another way to do this that might fit your use-case well. If you're using the global as something that affects the build of your first page, you could use an InheritedWidget to define your global user preferences, and each time they are changed your FirstPage will rebuild. This even works within a stateless widget as shown below (but should work in a stateful widget as well).

    An example of inheritedWidget in flutter is the app's Theme, although they define it within a widget instead of having it directly building as I have here.

    import 'package:flutter/material.dart';
    import 'package:meta/meta.dart';
    
    class SecondPage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return new Container(
          color: Colors.green,
          child: new Column(
            children: <Widget>[
              new RaisedButton(
                onPressed: () {
                  ColorDefinition.of(context).toggleColor();
                  Navigator.pop(context);
                },
                child: new Text("back"),
              ),
            ],
          ),
        );
      }
    }
    
    class ColorDefinition extends InheritedWidget {
      ColorDefinition({
        Key key,
        @required Widget child,
      }): super(key: key, child: child);
    
      Color color = Colors.white;
    
      static ColorDefinition of(BuildContext context) {
        return context.inheritFromWidgetOfExactType(ColorDefinition);
      }
    
      void toggleColor() {
        color = color == Colors.white ? Colors.grey : Colors.white;
        print("color set to $color");
      }
    
      @override
      bool updateShouldNotify(ColorDefinition oldWidget) =>
          color != oldWidget.color;
    }
    
    class FirstPage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        var color = ColorDefinition.of(context).color;
    
        return new Container(
          color: color,
          child: new Column(
            children: <Widget>[
              new RaisedButton(
                  child: new Text("next"),
                  onPressed: () {
                    Navigator.push(
                      context,
                      new MaterialPageRoute(builder: (context) => new SecondPage()),
                    );
                  }),
            ],
          ),
        );
      }
    }
    
    void main() => runApp(
          new MaterialApp(
            builder: (context, child) => new SafeArea(
                  child: new ColorDefinition(child: child),
                ),
            home: new FirstPage(),
          ),
        );
    

    If you use inherited widget you don't have to worry about watching for the pop of the page you pushed, which will work for basic use-cases but may end up having problems in a more complex scenario.

    0 讨论(0)
提交回复
热议问题