在Flutter中从有状态小部件返回数据

14

我之前发布过关于我仍在面临的问题的帖子,即如何将Stateful Widget中的数据返回到Stateless Widget。

我正在使用DateTimePickerFormField Widget,并将其作为Stateful Widget的子级使用。

因此,我查看了https://flutter.io/docs/cookbook/navigation/returning-data#complete-example来了解从widget返回数据的方法。然而,返回数据的widget是无状态的... 而在我的情况下不是这样的。

所以代码如下:

Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Add a Reminder'),

      ),
      body:
      new Container(
        padding: new EdgeInsets.all(20.0),
        child: new Form(
            child: new ListView(
              children: <Widget>[

            new TextFormField(
            keyboardType: TextInputType.text,
              // Use email input type for emails.
              decoration: new InputDecoration(
                hintText: 'Title of reminder',
              ),

            ),
            dateAndTimeWidget(context),
            RaisedButton(
            child: Text('Save'),
        onPressed: () {
          Navigator.pop(context);
        },
      )
      ],
    ),)
    ,
    )
    ,
    );

  }
那个 Widget 正在调用方法:dateAndTimeWidget,其应返回 dateTime stateful widget 并将输出数据保存到一个变量中。

那个 Widget 正在调用方法:dateAndTimeWidget,其应返回 dateTime stateful widget 并将输出数据保存到一个变量中:

 dateAndTimeWidget(BuildContext context) async {
    final result = await Navigator.push(
      context,
      MaterialPageRoute(builder: (context)=> dateTime()),
    );

}

那么这是日期时间状态小部件

class dateTime extends StatefulWidget{
    @override
  dateTimeState createState() => dateTimeState();

}
class dateTimeState extends State<dateTime>{

  static DateTime dateT;

  InputType inputType = InputType.both;

  final formats = {
    InputType.both: DateFormat("EEEE, MMMM d, yyyy 'at' h:mma"),
    InputType.date: DateFormat('yyyy-MM-dd'),
    InputType.time: DateFormat("HH:mm"),
  };

  Widget build(BuildContext context) => Container(
      child: DateTimePickerFormField(
        inputType: InputType.both,
        editable: true,
        format: formats[inputType],
        decoration: InputDecoration(
            labelText: 'Date/Time', hasFloatingPlaceholder: false),
        onChanged: (dt) {
          setState(() => dateT = dt);
          Navigator.of(context).pop(dateT);
        },

      )


  );


}

我尚未使用该值结果,因为错误在于我从未进入添加提醒页面,而且它显示结果推送导航方法指向 null。

2个回答

32
在这种情况下,使用Navigator传递数据并不适合。因为在页面和您的dateTime小部件之间没有页面转换。我建议您实现ValueChanged回调,在同一屏幕中的小部件之间传递数据。

示例代码:

这有点棘手。但是material.dart的小部件经常使用这种技术。我希望这可以帮助您!
class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  DateTime dateT;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Add a Reminder'),
      ),
      body: new Container(
        padding: new EdgeInsets.all(20.0),
        child: new Form(
          child: new ListView(
            children: <Widget>[
              new TextFormField(
                keyboardType: TextInputType.text,
                // Use email input type for emails.
                decoration: new InputDecoration(
                  hintText: 'Title of reminder',
                ),
              ),
              dateTime(
                onDateTimeChanged: (newDateTime) {
                  dateT = newDateTime;
                },
              ),
              RaisedButton(
                child: Text('Save'),
                onPressed: () {
                  Navigator.pop(context);
                },
              )
            ],
          ),
        ),
      ),
    );
  }
}

class dateTime extends StatefulWidget {
  final ValueChanged<DateTime> onDateTimeChanged;

  dateTime({Key key, this.onDateTimeChanged}) : super(key: key);

  @override
  dateTimeState createState() => dateTimeState();
}

class dateTimeState extends State<dateTime> {
  DateTime dateT;

  InputType inputType = InputType.both;

  final formats = {
    InputType.both: DateFormat("EEEE, MMMM d, yyyy 'at' h:mma"),
    InputType.date: DateFormat('yyyy-MM-dd'),
    InputType.time: DateFormat("HH:mm"),
  };

  Widget build(BuildContext context) => Container(
        child: DateTimePickerFormField(
          inputType: InputType.both,
          editable: true,
          format: formats[inputType],
          decoration: InputDecoration(
              labelText: 'Date/Time', hasFloatingPlaceholder: false),
          onChanged: (dt) {
            widget.onDateTimeChanged(dt);
          },
        ),
      );
}

顺便提一下,您的dateAndTimeWidget是一个方法,而不是小部件。因此,如果您将其分配给列的子项(列表),Flutter框架将无法理解。


10

为了更好地节省时间,从另一个小部件返回值并使用它的解决方案,在这里给出了一个Flutter Dropdown的示例:

import 'package:flutter/material.dart';
import 'package:paxi_ride/constant.dart';

class BuildDropdown extends StatefulWidget {
  final ValueChanged<String> onChanged;
  String defaultValue, selectedValue, dropdownHint;
  List<String> itemsList;

  BuildDropdown(
      {Key key,
      this.itemsList,
      this.defaultValue,
      this.dropdownHint,
      this.onChanged})
      : super(key: key);

  @override
  _BuildDropdownState createState() => _BuildDropdownState();
}

class _BuildDropdownState extends State<BuildDropdown> {
  String _value;

  @override
  Widget build(BuildContext context) {
    return Container(
      // height: 40,
      padding: EdgeInsets.symmetric(horizontal: 16, vertical: 0),
      margin: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
      color: Colors.white,
      child: DropdownButton<String>(
        items: widget.itemsList.map(
          (String value) {
            return new DropdownMenuItem<String>(
              value: value,
              child: new Text(value),
            );
          },
        ).toList(),
        value: _value == null ? widget.defaultValue : _value,
        isExpanded: true,
        onChanged: (String value) {
          setState(() {
            _value = value;
          });
          widget.onChanged(value);
        },
        hint: Text(widget.dropdownHint),
        style: TextStyle(
          fontSize: 14,
          color: brownColorApp,
        ),
        iconEnabledColor: brownColorApp,
        iconSize: 14,
        underline: Container(),
      ),
    );
  }
}

从另一个您想要获取选定值的小部件中调用此小部件:

String selectedValue; //class field

BuildDropdown(
          itemsList: ['Option 1','Option 2'],
          defaultValue: 'Option 1',
          dropdownHint: 'Select Required Option',
          onChanged: (value) {
            selectedValue = value;
          },
        ),

在需要的任何地方使用此值,当下拉选择更改时,它将被更改。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接