如何将数据从子窗口小部件传递到其父窗口

时间:2018-04-13 20:11:58

标签: dart flutter

我创建了Switch下面的自定义窗口小部件并读取其状态(true / false)

然后我将这个添加到我的主app小部件(父级)中,如何让父级知道切换的值!

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)),
          ],
        ),
      ),
    );
  }
}

main.dart(父)文件中,我从这开始:

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();
  //...

}

5 个答案:

答案 0 :(得分:16)

第一种可能性是将回调传递给您的孩子,第二种方法是将of模式用于您的有状态小部件。见下文。

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

还可以使用InheritedWidget而不是StatefulWidget;如果您希望子窗口小部件在父窗口小部件的数据发生更改且父级不是直接父级时重建,则此功能特别有用。请参阅inherited widget documentation

答案 1 :(得分:3)

在2020年,投票最高的答案中的功能被标记为已弃用。因此,这是基于该答案的修改后的解决方案:

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

答案 2 :(得分:3)

我认为通知是一种非常文明的解决方案,它们允许进行非常干净的交流,而无需进行各种变通,如果您需要它们,它们会冒泡:

定义通知:

class SwitchChanged extends Notification {
  final bool val
  SwitchChanged(this.val);
}

在您孩子的事件处理程序中引发通知:

onPressed: () {
  SwitchChanged(true).dispatch(context);
}

最后,用通知监听器包裹你的父级:

NotificationListener<ItemChangedNotification>(
  child: YourParent(...),
  onNotification: (n) {
    setState(() {
      // Trigger action on parent via setState or do whatever you like.
    });
    return true;
  }
)

答案 3 :(得分:2)

输出:

enter image description here

通常您使用Navigator.pop(context, "your data here");,但您也可以通过这种方式传递数据

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

答案 4 :(得分:0)

使用InheritedWidget-https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html

这使您可以访问所有子代中父代的数据