在屏幕之间传递数据但使用提取的下拉按钮小部件

Passing data between screen but using extracted dropdown button widget

首先,这是我的条件。我正在尝试将第一个屏幕(左图)的下拉按钮和日期和时间选择器中填写的所有数据传递到第二个屏幕(右图)。问题是,我将 DropDownButton 小部件提取到另一个 class,但我不明白如何实现它。

在此之前,这是第一个屏幕代码:

  class InformationDetail extends StatefulWidget {
  static const String id = 'InformationDetail';
  @override
  _InformationDetailState createState() => _InformationDetailState();
}

class _InformationDetailState extends State<InformationDetail> {
  String addressText, addNotes;
  DateTime selectedDate = DateTime.now();
  TimeOfDay selectedTime = TimeOfDay.now();

  Future<Null> _selectDate(BuildContext context) async {
    final DateTime picked = await showDatePicker(
        context: context,
        initialDate: selectedDate,
        firstDate: DateTime(2015, 8),
        lastDate: DateTime(2101));
    if (picked != null && picked != selectedDate)
      setState(() {
        selectedDate = picked;
      });
  }

  Future<Null> _selectTime(BuildContext context) async {
    final TimeOfDay picked = await showTimePicker(
      context: context,
      initialTime: selectedTime,
    );
    if (picked != null && picked != selectedTime)
      setState(() {
        selectedTime = picked;
      });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
          child: ListView(
        children: <Widget>[
          Container(
            child: Column(
              children: <Widget>[
                Container(
                  margin: EdgeInsets.fromLTRB(25.0, 68.0, 70.0, 26.0),
                  child: Text(
                    'Information Detail',
                    style: TextStyle(fontSize: 35.0),
                  ),
                ),
                Column(
                  // Wrap Column
                  children: <Widget>[
                    Column(
                      children: <Widget>[
                        TitleName(
                          titleText: 'Grooming Type',
                          infoIcon: Icons.info,
                        ),
                        MenuDropDown(
                          dropdownText: 'Grooming Type...',
                          type: "groomingType",
                        ),
                        TitleName(
                          titleText: 'Cat Breeds',
                        ),
                        MenuDropDown(
                          dropdownText: 'Cat Breeds...',
                          type: "catBreeds",
                        ),
                        TitleName(
                          titleText: 'Cat Size',
                          infoIcon: Icons.info,
                        ),
                        MenuDropDown(
                          dropdownText: 'Cat Size...',
                          type: "catSize",
                        ),
                        TitleName(
                          titleText: 'Add-On Services',
                        ),
                        MenuDropDown(
                          dropdownText: 'Add - On Services...',
                          type: "addOnServices",
                        ),
                        TitleName(
                          titleText: 'Reservation Date',
                        ),
                        Row(
                          children: <Widget>[
                            Container(
                              width: 130,
                              height: 30,
                              margin: EdgeInsets.fromLTRB(50.0, 0, 62, 0),
                              child: RaisedButton(
                                color: Colors.white,
                                shape: RoundedRectangleBorder(
                                  borderRadius: BorderRadius.circular(15.0),
                                ),
                                elevation: 6,
                                child: Text(
                                  'Choose Date',
                                  style: TextStyle(
                                    fontSize: 12.0,
                                  ),
                                ),
                                onPressed: () => _selectDate(context),
                              ),
                            ),
                            Text("${selectedDate.toLocal()}".split(' ')[0]),
                          ],
                        ),
                        TitleName(
                          titleText: 'Reservation Time',
                        ),
                        Row(
                          children: <Widget>[
                            Container(
                              width: 130,
                              height: 30,
                              margin: EdgeInsets.fromLTRB(50.0, 0, 62, 0),
                              decoration: BoxDecoration(),
                              child: RaisedButton(
                                color: Colors.white,
                                child: Text(
                                  'Choose Time',
                                  style: TextStyle(
                                    fontSize: 12.0,
                                  ),
                                ),
                                shape: RoundedRectangleBorder(
                                  borderRadius: BorderRadius.circular(15.0),
                                ),
                                elevation: 6,
                                onPressed: () => _selectTime(context),
                              ),
                            ),
                            Text("${selectedTime.toString()}".split(' ')[0]),
                          ],
                        ),
                        TitleName(
                          titleText: 'Pick Up Address',
                        ),
                        Container(
                          width: 320,
                          height: 40,
                          child: TextFormField(
                            maxLines: null,
                            minLines: null,
                            expands: true,
                            decoration: InputDecoration(
                              contentPadding:
                                  EdgeInsets.fromLTRB(35.0, 10.0, 0, 10.0),
                              hintText: 'Address Here...',
                              hintStyle: TextStyle(
                                fontSize: 15.0,
                              ),
                              border: OutlineInputBorder(
                                borderRadius: BorderRadius.circular(15.0),
                              ),
                            ),
                            onChanged: (value) {
                              addressText = value;
                            },
                          ),
                        ),
                        TitleName(
                          titleText: 'Additional Notes',
                          infoIcon: Icons.info,
                        ),
                        Container(
                          width: 320,
                          child: TextFormField(
                            maxLines: 4,
                            decoration: InputDecoration(
                              contentPadding:
                                  EdgeInsets.fromLTRB(35.0, 10.0, 0, 10.0),
                              hintText: 'E.g. ',
                              hintStyle: TextStyle(
                                fontSize: 15.0,
                              ),
                              border: OutlineInputBorder(
                                borderRadius: BorderRadius.circular(15.0),
                              ),
                            ),
                            onChanged: (value) {
                              addNotes = value;
                            },
                          ),
                        ),
                        Container(
                          margin: EdgeInsets.fromLTRB(0, 15.0, 0, 0),
                          width: 75.0,
                          decoration: BoxDecoration(
                            color: Colors.white,
                            shape: BoxShape.rectangle,
                            border: Border.all(
                              color: Colors.black,
                            ),
                            borderRadius: BorderRadius.circular(12.0),
                          ),
                          child: IconButton(
                              icon: Icon(Icons.arrow_forward),
                              onPressed: () {
                                Navigator.of(context).push(MaterialPageRoute(
                                    builder: (context) => ConfirmationOrder(
                                          addressText: addressText,
                                          addNotes: addNotes,
                                        )));
                              }),
                        ),
                      ],
                    ),
                  ],
                ),
              ],
            ),
          ),
        ],
      )),
    );
  }
}

在第一张图片下方,有一个导航到第二个屏幕的按钮。

这是我提取 DropDownButton 的 class :

    class MenuDropDown extends StatefulWidget {
  final String dropdownText;
  final String type;
  MenuDropDown({this.dropdownText, this.type});
  @override
  _MenuDropDownState createState() => _MenuDropDownState();
}

class _MenuDropDownState extends State<MenuDropDown> {
  String selectedItem;
  List<String> dropdownItems = [];

  List<String> groomingTypeList = ['Basic Grooming', 'Full Grooming'];

  List<String> catBreedsList = [
    'Persia',
    'Anggora',
    'Domestic',
    'Maine Coon',
    'Russian Blue',
    'Slamese',
    'Munchkin',
    'Ragdoll',
    'Scottish Fold',
  ];

  List<String> catSizeList = [
    'Small Size',
    'Medium Size',
    'Large Size',
    'Extra Large Size',
  ];

  List<String> addOnServicesList = [
    'Spa & Massage',
    'Shaving Hair / Styling',
    'Injection Vitamis Skin & Coat',
    'Cleaning Pet House and Environment',
    'Fur Tangled Treatment',
  ];

  List<String> getListBasedOnName(String value) {
    print(value);
    switch (value) {
      case "groomingType":
        return groomingTypeList;

        break;
      case "catBreeds":
        return catBreedsList;
        break;

      case "catSize":
        return catSizeList;
        break;
      case "addOnServices":
        return addOnServicesList;
        break;
    }

    return null;
  }

  @override
  void initState() {
    super.initState();
    print(widget.type);

    dropdownItems = getListBasedOnName(widget.type);
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.fromLTRB(0, 8.0, 0, 10.0),
      child: Container(
        width: 325.0,
        height: 50.0,
        decoration: BoxDecoration(
          boxShadow: [
            BoxShadow(
              color: Colors.black45,
              offset: Offset(2.5, 5.5),
              blurRadius: 5.0,
            )
          ],
          borderRadius: BorderRadius.circular(8),
          color: Colors.white,
        ),
        child: DropdownButtonHideUnderline(
          child: DropdownButton(
              value: selectedItem,
              hint: Padding(
                padding: const EdgeInsets.fromLTRB(22.0, 0, 0, 0),
                child: Text(
                  widget.dropdownText,
                  style: TextStyle(),
                ),
              ),
              items: dropdownItems.map((String value) {
                return new DropdownMenuItem<String>(
                  value: value,
                  child: new Text(value),
                );
              }).toList(),
              onChanged: (value) {
                setState(() {
                  selectedItem = value;
                });
              }),
        ),
      ),
    );
  }
}

我真的很困惑,因为 DropDownButton 中的 onChanged 函数已经被使用了。我几乎无法从文本小部件中完成正常的传递数据。但是从下拉按钮和日期和时间选择器,我不知道该怎么做。

有没有什么方法可以从首屏获取数据,因为目前我还没有学习状态管理或Bloc。而且代码仍然很乱我还没有完成重构。真心希望大家帮忙解决,谢谢!

首先,对于 MenuDropDown,您需要对 onChanged 方法进行某种扩展。向小部件的构造函数添加一个 VoidCallback 参数,如下所示:

typedef OnChangeCallback = void Function(dynamic value);

class MenuDropDown extends StatefulWidget {
  final String dropdownText;
  final String type;
  final OnChangeCallback onChanged;

  MenuDropDown({this.dropdownText, this.type, this.onChanged});

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

并在状态下调用该方法作为 DropdownButton 的本机 onChanged 回调的一部分:

onChanged: (value) {
  setState(() {
    selectedItem = value;
  });
  widget.onChanged(value);
}

并且在 _InformationDetailState 中,您将为每个输入字段存储当前选择的项目并传递一个 onChanged 函数来更新每个输入的相应字段:

String catSize; //Declare at the top of _InformationDetailState
...
MenuDropDown(
  dropdownText: 'Cat Size...',
  type: "catSize",
  onChanged: (value) {
    catSize = value;
  }
),

现在将数据传递到下一个屏幕。在您的应用程序中使用任何类型的状态管理从来都不是绝对必要的,而且我发现很多人不必要地使用它。在您的情况下,绝对没有必要仅将数据传递给其他单个小部件。您已经正确传递了 addressTextaddNotes。只需为您需要在确认屏幕上显示的每个参数扩展它。或者,您可以将所有字段存储在一个 Map 中,而不是每个字段都有一个变量,然后将 Map 传递到确认页面。