How to pass data from child widget to its parent

后端 未结 3 567
故里飘歌
故里飘歌 2020-12-02 10:29

I\'ve the below custom widget that make a Switch and reads its status (true/false)

Then I add this one to my main app widget (parent), how can I make th

相关标签:
3条回答
  • 2020-12-02 11:09

    The first possibility is to pass a callback into your child, and the second is to use the of pattern for your stateful widget. See below.

    import 'package:flutter/material.dart';
    
    class MyStatefulWidget extends StatefulWidget {
      @override
      State<StatefulWidget> createState() => new MyStatefulWidgetState();
    
      static MyStatefulWidgetState of(BuildContext context) {
        final MyStatefulWidgetState navigator =
            context.ancestorStateOfType(const TypeMatcher<MyStatefulWidgetState>());
    
        assert(() {
          if (navigator == null) {
            throw new FlutterError(
                'MyStatefulWidgetState operation requested with a context that does '
                'not include a MyStatefulWidget.');
          }
          return true;
        }());
    
        return navigator;
      }
    }
    
    class MyStatefulWidgetState extends State<MyStatefulWidget> {
      String _string = "Not set yet";
    
      set string(String value) => setState(() => _string = value);
    
      @override
      Widget build(BuildContext context) {
        return new Column(
          children: <Widget>[
            new Text(_string),
            new MyChildClass(callback: (val) => setState(() => _string = val))
          ],
        );
      }
    }
    
    typedef void StringCallback(String val);
    
    class MyChildClass extends StatelessWidget {
      final StringCallback callback;
    
      MyChildClass({this.callback});
    
      @override
      Widget build(BuildContext context) {
        return new Column(
          children: <Widget>[
            new FlatButton(
              onPressed: () {
                callback("String from method 1");
              },
              child: new Text("Method 1"),
            ),
            new FlatButton(
              onPressed: () {
                MyStatefulWidget.of(context).string = "String from method 2";
              },
              child: new Text("Method 2"),
            )
          ],
        );
      }
    }
    
    void main() => runApp(
          new MaterialApp(
            builder: (context, child) => new SafeArea(child: new Material(color: Colors.white, child: child)),
            home: new MyStatefulWidget(),
          ),
        );
    

    There is also the alternative of using an InheritedWidget instead of a StatefulWidget; this is particularly useful if you want your child widgets to rebuild if the parent widget's data changes and the parent isn't a direct parent. See the inherited widget documentation

    0 讨论(0)
  • 2020-12-02 11:14

    Output:

    Generally you use Navigator.pop(context, "your data here"); but you can also pass the data in this manner

    class ParentScreen extends StatefulWidget {
      @override
      _ParentScreenState createState() => _ParentScreenState();
    }
    
    class _ParentScreenState extends State<ParentScreen> {
      String _text = "";
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(title: Text("Parent screen")),
          body: Column(
            children: <Widget>[
              RaisedButton(
                child: Text("GO TO CHILD"),
                onPressed: () => Navigator.push(context, MaterialPageRoute(builder: (_) => ChildScreen(func: function))),
              ),
              Text(_text),
            ],
          ),
        );
      }
    
      function(value) => setState(() => _text = value);
    }
    
    class ChildScreen extends StatelessWidget {
      final Function func;
    
      const ChildScreen({Key key, this.func}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(title: Text("Child screen")),
          body: RaisedButton(
            child: Text("BACK TO PARENT"),
            onPressed: () {
              func("This is the data which child has passed"); // passing data to parent
              Navigator.pop(context);
            },
          ),
        );
      }
    }
    
    0 讨论(0)
  • 2020-12-02 11:14

    In 2020, the function in the highest voted answer is marked deprecated. So here is the modified solution based on that answer:

    import 'package:flutter/material.dart';
    
    class MyStatefulWidget extends StatefulWidget {
      @override
      State<StatefulWidget> createState() => new MyStatefulWidgetState();
    
      // --> NOTE this! <--
      static MyStatefulWidgetState of(BuildContext context) =>
        context.findAncestorStateOfType<MyStatefulWidgetState>();
    }
    
    class MyStatefulWidgetState extends State<MyStatefulWidget> {
      String _string = "Not set yet";
    
      set string(String value) => setState(() => _string = value);
    
      @override
      Widget build(BuildContext context) {
        return new Column(
          children: <Widget>[
            new Text(_string),
            new MyChildClass(callback: (val) => setState(() => _string = val))
          ],
        );
      }
    }
    
    typedef void StringCallback(String val);
    
    class MyChildClass extends StatelessWidget {
      final StringCallback callback;
    
      MyChildClass({this.callback});
    
      @override
      Widget build(BuildContext context) {
        return new Column(
          children: <Widget>[
            new FlatButton(
              onPressed: () {
                callback("String from method 1");
              },
              child: new Text("Method 1"),
            ),
            new FlatButton(
              onPressed: () {
                MyStatefulWidget.of(context).string = "String from method 2";
              },
              child: new Text("Method 2"),
            )
          ],
        );
      }
    }
    
    void main() => runApp(
          new MaterialApp(
            builder: (context, child) => new SafeArea(child: new Material(color: Colors.white, child: child)),
            home: new MyStatefulWidget(),
          ),
        );
    
    0 讨论(0)
提交回复
热议问题