Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass data from child widget to its parent

Tags:

flutter

dart

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 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();   //...  } 
like image 837
Hasan A Yousef Avatar asked Apr 13 '18 20:04

Hasan A Yousef


People also ask

How do you pass data from a child widget to a parent widget in flutter?

There's (at least) two ways to pass data from a child widget to a parent widget in Flutter; Shared object using Singleton pattern or callbacks.

How pass data between widgets in flutter?

Steps to Pass Data to Stateful Widget in Flutter To pass data to stateful widget, first of all, create two pages. Now from the first page open the second page and pass the data. Inside the second page, access the variable using the widget. For example widget.

How do you call a method of a child widget from parent in flutter?

Calling a method of child widget from a parent widget is discouraged in Flutter. Instead, Flutter encourages you to pass down the state of a child as constructor parameters. Hence instead of calling a method of the child, you just call setState in the parent widget to update its children.

What is parent widget in flutter?

This can be used to provide per-child configuration for RenderObjectWidgets with more than one child. For example, Stack uses the Positioned parent data widget to position each child. A ParentDataWidget is specific to a particular kind of ParentData.


2 Answers

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(),       ),     ); 

However, the methods mentioned in the answers of this question has a drawback. From doc:

In general, though, consider using a callback that triggers a stateful change in the ancestor rather than using the imperative style implied by this method. This will usually lead to more maintainable and reusable code since it decouples widgets from each other.

Calling this method is relatively expensive (O(N) in the depth of the tree). Only call this method if the distance from this widget to the desired ancestor is known to be small and bounded.

like image 34
ch271828n Avatar answered Sep 23 '22 15:09

ch271828n


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

like image 116
rmtmckenzie Avatar answered Sep 25 '22 15:09

rmtmckenzie