dartflutter

How to pass data from child widget to its parent


I have the below custom widget that makes a Switch and reads its status (true/false)

Then I add this one to my main app widget (parent), how can I make the parent knows the value of the switch?

import 'package:flutter/material.dart';

class Switchy extends StatefulWidget{
  Switchy({Key key}) : super(key: key);

  @override
  State<StatefulWidget> createState() => new _SwitchyState();
  }

class _SwitchyState extends State<Switchy> {
  var myvalue = true;

  void onchange(bool value) {
    setState(() {
      this.myvalue = value;      // I need the parent to receive this one!
      print('value is: $value');
    });
  }

  @override
  Widget build(BuildContext context) {
    return             
      new Card(
      child: new Container(
        child: new Row(
          mainAxisAlignment: MainAxisAlignment.end,
          children: <Widget>[
            new Text("Enable/Disable the app in the background",
              textAlign: TextAlign.left,
              textDirection: TextDirection.ltr,),
            new Switch(value: myvalue, onChanged: (bool value) => onchange(value)),
          ],
        ),
      ),
    );
  }
}

In the main.dart (parent) file, I started with this:

import 'widgets.dart';
import 'package:flutter/material.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.deepOrange,
      ),
      home: new MyHomePage(title: 'My App settup'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  Widget e = new Switchy();
  //...

}

Solution

  • 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();
    
      // note: updated as context.ancestorStateOfType is now deprecated
      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(),
      ),
    );
    

    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