【问题标题】:Dart / flutter: DropdownButton causes exception when value is changedDart / flutter:DropdownButton在值更改时导致异常
【发布时间】:2018-10-27 07:23:00
【问题描述】:

我使用DropdownButtonTextField 小部件编写了一个相当广泛的表单。这个概念是我有一个StatefulWidget,其中State<StatefulWidget> 的类包含2 个返回我想要构建的小部件的方法。通过这种方式,我可以轻松访问和使用输入的数据,并将其传递给一个函数来编写一封电子邮件。

但是,当我从选项中选择一个项目时,框架会在重建期间引发异常。我输入了一些日志函数,显示setState()方法成功将值保存到selectedValue变量中。

Widget buildMultiChoiceInputRow(var label, List<String> values) {
    final List<String> options = values.toList();
    selection = options.first;

    final dropDownMenuOptions = options.map((String value) {
      return new DropdownMenuItem<String>(
        value: value,
        child: new Text(value),
      );
    }).toList();

    return new Column(
      children: <Widget>[
        new Row(
          children: <Widget>[
            new Expanded(
              child: new Container(
                  padding:
                      const EdgeInsets.only(left: 5.0, top: 2.0, right: 5.0),
                  child: new Text(label, style: commonInfoCardInfoTextBlack16Bold)),
            ),
          ],
        ),
        new Row(
          children: <Widget>[
            new Expanded(
              child: new Container(
                padding: const EdgeInsets.only(left: 5.0, right: 5.0),
                child: new DropdownButton(
                value: selectedValue,
                items: dropDownMenuOptions,
                onChanged: (selection) {
                  setState(() {
                    selectedValue = selection;
                    switch (label) {
                      case labelVirtualAdoption:
                        tempAdoptionType =
                            composeMultiChoiceAnswer(label, selection);
                            print(selection);
                            print(selectedValue);
                        break;
                          case labelAskedAboutSpecies:
                            tempAskedAboutSpecies =
                                composeMultiChoiceAnswer(label, selection);
                            break;
                          case labelHouseOrFlat:
                            tempHouseOrFlat =
                                composeMultiChoiceAnswer(label, selection);
                            break;
                            ....
                          default:
                            break;
                        }
                      });
                    }),
              ),
            )
          ],
        ),
        new Divider(color: Colors.transparent)
      ],
    );
  }

这是一个例外:

I/flutter (20998): The following assertion was thrown building AdoptionInput(dirty, state: AdoptionInputState#3cc80):
I/flutter (20998): 'package:flutter/src/material/dropdown.dart': Failed assertion: line 481 pos 15: 'value == null ||
I/flutter (20998): items.where((DropdownMenuItem<T> item) => item.value == value).length == 1': is not true.

这里是堆栈,显示在重建期间抛出了异常:

I/flutter (20998): #2      new DropdownButton (package:flutter/src/material/dropdown.dart)
I/flutter (20998): #3      AdoptionInputState.buildMultiChoiceInputRow (package:osszefogasaszanhuzokert/adoptionPageUtilities.dart:443:28)
I/flutter (20998): #4      AdoptionInputState.build (package:osszefogasaszanhuzokert/adoptionPageUtilities.dart:639:11)
I/flutter (20998): #5      StatefulElement.build (package:flutter/src/widgets/framework.dart:3730:27)
I/flutter (20998): #6      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3642:15)
I/flutter (20998): #7      Element.rebuild (package:flutter/src/widgets/framework.dart:3495:5)
I/flutter (20998): #8      BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2242:33)

问题似乎与a former bug in flutter 非常相似,但是如果我尝试在initState() 中初始化selectionselectedValue,则会在第一次构建表单时抛出相同的异常。

我在这里错过了什么?

【问题讨论】:

  • 与此同时,我发现当构建具有与“igen”“nem”不同的值(或者我认为与我使用的第一个不同)的小部件时会引发异常

标签: dart flutter


【解决方案1】:

DropdownButton 的“值”应设置为“null”或值列表中的一个。

DropdownButton(
      value: null,
      isDense: true,
      onChanged: (String newValue) {
        // somehow set here selected 'value' above whith 
       // newValue
       // via setState or reactive.
      },
      items: ['yellow', 'brown', 'silver'].map((String value) {
        return DropdownMenuItem(
          value: value,
          child: Text(value),
        );
      }).toList(),
    ),

因此对于我的示例 DropdownButton 值应设置为 null 或为“黄色”或“棕色”或“银色”。

【讨论】:

  • 但是在 make select: null 之后,选择的值没有显示在下拉列表中
  • 是选择的值未显示?有什么办法可以解决这个问题
【解决方案2】:

用我被卡住的第二种情况扩展上述答案。

DropdownButton 的“值”应设置为“null”或值列表中的一个。

您的“价值”也应该在每个项目的价值中有所不同。

例如:避免这种情况

 items.add(DropdownMenuItem(
  value: 1.toString(),
  child: Text(1.toString()),
));
items.add(DropdownMenuItem(
  value: 1.toString(),
  child: Text(1.toString()),
));

避免重复值。

【讨论】:

    【解决方案3】:

    使用 var 来声明变量而不是 String。现在您不需要将默认值设置为 null。

    var dropdownvalue;
    
    DropdownButton<String>(
                        value: dropdownvalue,
                        icon: Icon(Icons.keyboard_arrow_down),
                        iconSize: 28,
                        elevation: 20,
                        onChanged: (String newval){
                          setState((){
                            dropdownvalue = newval;
                          });
    
                        },
                        items: <String>["Registration","Verification", "ArenaRun"]
                            .map<DropdownMenuItem<String>>((String value){
                          return DropdownMenuItem<String>(
                            value: value,
                            child: Text(value),
                            );
                        }).toList(),
                      ),
    

    【讨论】:

      【解决方案4】:

      有点休息时间,但是,当我将 null 作为“值”传递时,代码可以工作,但是当我放置一个包含在“项目”中的值时,我遇到了这个问题。问题是“Items”具有重复值,因此您似乎应该提供传递给“Items”的列表中的所有不同项目。

      【讨论】:

        【解决方案5】:

        这是正确的方法:

         import 'package:flutter/material.dart';
        
        class RegisterFragments extends StatefulWidget {
          RegisterFragments({Key key, this.step}) : super(key: key);
          final int step;
        
          _RegisterFragmentsState createState() => _RegisterFragmentsState();
        }
        
        class _RegisterFragmentsState extends State<RegisterFragments> {
          Map<String, bool> values = {"abc": false, "def": true, "ghi": false};
          List<String> _do = ['One', 'Two', 'Free', 'Four'];
          String _dropdownValue = 'One';
        
          @override
          Widget build(BuildContext context) {
            switch (widget.step) {
              case 0:
                return buildDo();
                break;
              case 1:
                return Container(
                  child: ListView.builder(
                    shrinkWrap: true,
                    itemCount: values.length,
                    itemBuilder: (BuildContext context, int index) {
                      switch (widget.step) {
                        case 0:
                          return buildDo();
                          break;
                        case 1:
                          return buildService(context, index);
                          break;
                        default:
                          return Container();
                          break;
                      }
                    },
                  ),
                );
                break;
              default:
                return Container();
                break;
            }
          }
        
          Widget buildService(BuildContext context, int index) {
            String _key = values.keys.elementAt(index);
        
            return Container(
              child: Card(
                child: CheckboxListTile(
                  title: Text(_key),
                  onChanged: (bool value) {
                    setState(() {
                      values[_key] = value;
                    });
                  },
                  value: values[_key],
                ),
              ),
            );
          }
        
          Widget buildDo() {
            return DropdownButton<String>(
              isExpanded: true,
              hint: Text("Service"),
              items: _do.map<DropdownMenuItem<String>>((String value) {
                return DropdownMenuItem<String>(
                  value: value,
                  child: Text(value),
                );
              }).toList(),
              onChanged: (String newValue) {
                setState(() {
                  this._dropdownValue = newValue;
                });
              },
              value: _dropdownValue,
            );
          }
        }
        

        list 和 dorpdown 值

           List<String> _do = ['One', 'Two', 'Free', 'Four'];
           String _dropdownValue = 'One';
        

        下拉项目

        tems: _do.map<DropdownMenuItem<String>>((String value) {   
          return DropdownMenuItem<String>( ** 
             value: value,
                  child: Text(value),
                );
              }).toList(),
              onChanged: (String newValue) {
                setState(() {
                  this._dropdownValue = newValue;
                });
              },
              value: _dropdownValue,
        

        【讨论】:

        • 请添加 cmets 并突出显示您所做的与海报不同的部分。
        【解决方案6】:

        我正在执行 value.toString() 并且 null 被转换为“null”!

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-02-12
          • 2020-02-04
          • 1970-01-01
          • 2018-09-03
          • 1970-01-01
          • 2013-04-22
          相关资源
          最近更新 更多