Flutter:应该只有[DropdownButton]值的一项

时间:2020-03-03 15:06:59

标签: flutter dart drop-down-menu dropdownbutton flutter-futurebuilder

我正在尝试在Flutter中创建一个下拉按钮。我从数据库中获取了一个列表,然后将该列表传递给了我的 if (ignoreCorruptFiles) { currentIterator = new NextIterator[Object] { // The readFunction may read some bytes before consuming the iterator, e.g., // vectorized Parquet reader. Here we use lazy val to delay the creation of // iterator so that we will throw exception in `getNext`. private lazy val internalIter = readCurrentFile() override def getNext(): AnyRef = { try { if (internalIter.hasNext) { internalIter.next() } else { finished = true null } } catch { // Throw FileNotFoundException even `ignoreCorruptFiles` is true case e: FileNotFoundException => throw e case e @ (_: RuntimeException | _: IOException) => logWarning( s"Skipped the rest of the content in the corrupted file: $currentFile", e) finished = true null } } 一切正常,数据显示为预期的,但当我选择一个元素,我收到此错误:

dropdownButton

我尝试将 DropdownButton值设置为null ,但可以,但是我看不到所选元素

这是我的代码:

There should be exactly one item with [DropdownButton]'s value: Instance of 'Tag'. 
Either zero or 2 or more [DropdownMenuItem]s were detected with the same value
'package:flutter/src/material/dropdown.dart':
Failed assertion: line 805 pos 15: 'items == null || items.isEmpty || value == null ||
          items.where((DropdownMenuItem<T> item) {
            return item.value == value;
          }).length == 1'

我使用 futureBuilder 从数据库中获取列表

12 个答案:

答案 0 :(得分:26)

好吧,因为没有问题有完全相同的解决方案。我的代码也面临同样的问题。这是我的解决方法。

我的DropdownButton的代码:

DropdownButton(
   items: _salutations
         .map((String item) =>
             DropdownMenuItem<String>(child: Text(item), value: item))
         .toList(),
    onChanged: (String value) {
       setState(() {
         print("previous ${this._salutation}");
         print("selected $value");
         this._salutation = value;
            });
          },
     value: _salutation,
),

错误

在下面的代码段中,我设置了选择类型为String的状态。现在我的代码有问题是此选择值的默认初始化。 最初,我将变量_salutation初始化为:

String _salutation = ""; //Notice the empty String.

这是一个错误!

初始选择不应为null或为空,因为正确提到了错误消息。

'items == null || items.isEmpty ||值== null ||

因此而崩溃:

crash_message

解决方案
用一些默认值初始化值对象。 请注意值应该是集合中包含的值之一。如果不是,则可能会导致崩溃。

  String _salutation = "Mr."; //This is the selection value. It is also present in my array.
  final _salutations = ["Mr.", "Mrs.", "Master", "Mistress"];//This is the array for dropdown

答案 1 :(得分:4)

如果尝试使用类实例设置dropdown的值,也可能会收到此错误;

  var tag1 = Tag();
  var tag2 = Tag();
  print(tag1 == tag2); // prints false, dropwdown computes that value is not present among dropdown options

要解决此替代运算符==:

class Tag{
 String name = "tag";

  @override
  bool operator ==(Object other) => other is Tag && other.name == name;

  @override
  int get hashCode => name.hashCode;
}

或使用https://pub.dev/packages/equatable lib

class Tag extends Equatable{
 String name = "tag";

  @override
  List<Object> get props => [name];
}

答案 2 :(得分:2)

我的下拉菜单代码

child: DropdownButton(
      items: _currencies.map((String value) {
        return DropdownMenuItem<String>(
          child: Text(value),
          value: value,
        );
      }).toList(),
      value: 'Rupees',
      onChanged: (String newValueSelected) {
        // Your code to execute, when a menu item is selected from 
        dropdown
      },
))
var _currencies = ['Rupee','Dollar','Pound'];

我遇到了同样的错误,因为下拉代码块中的值与_currencies中的任何字段都不匹配

答案 3 :(得分:1)

所以我找到了一个解决方案

创建了一个空列表来保存我的标签对象

List<Tag> _tagList = [];

然后,在我的 initState 中,我分配我从数据库获得的列表上一个列表

 @override
void initState() {
super.initState();
_tagDatabaseHelper.getTagList().then((foo) {
  setState(() {
    _tagList = foo;
  });
});

}

最后我的DropdownButton代码:

DropdownButton<Tag>(
            isExpanded: true,
            icon: Icon(
              Icons.arrow_drop_down,
              size: 24,
            ),
            hint: Text(
              "Select tags",
              style: TextStyle(color: Color(0xFF9F9F9F)),
            ),
            items: _tagList.map((foo) {
              return DropdownMenuItem(
                value: foo,
                child: Text(foo.tagTitle),
              );
            }).toList(),
            onChanged: (value) {
              setState(() {
                _selectedTag = value;
              });
            },
            value: _selectedTag,
          ),

答案 4 :(得分:0)

只需使标记类从Equatable扩展并将属性传递给道具即可。这对我来说很成功。

class Tag extends Equatable{
  String id;
  String name;

  Tag(this.id, this.name);

  @override
  List<Object> get props => [id,name];

}

答案 5 :(得分:0)

我有同样的问题。解决方案很简单:您必须确保您要在下拉菜单中使用的列表中包含默认的下拉值字符串。假设要使用api中的列表,则应确保至少知道该列表的一个值,以便可以将其分配给默认dropdownvalue变量。

在这里,我要显示从api获取的列表。为了不出错,我将默认的dropdownvalue设置为名称“ Encajes”,这是列表包含的现有类别之一。

String dropdownValue = "Encajes";

    items: categoriesString
    .map<DropdownMenuItem<String>>((String value) {
  return DropdownMenuItem<String>(
    value: value,
    child: Text(value),
  );
}).toList(),

答案 6 :(得分:0)

我遇到了同样的问题,令人惊讶的是,从远程数据库中获取的项目列表中有重复项。

每次我从服务器获取数据时(当有新的应用程序用户登录时),这些数据没有重复,但是同一数据被多次添加到列表中,因为我是在同一设备上登录多个用户的。也许您的错误是类似的。

因此,请确保在 snapshot.data 删除所有重复项 >。

答案 7 :(得分:0)

您可以使用三元运算符避免空值:

  Container(
             child:
              new DropdownButton<String>(
              value: dropdownValue ?? "1",
              icon: const Icon(Icons.arrow_downward),
              iconSize: 24,
              elevation: 16,
              style: const TextStyle(color: Colors.black, fontSize: 18),
              underline: Container(height: 2, color: Colors.white24, ),
              items: <String>['1', '2', '3', '5'].map((String value) {
              return new DropdownMenuItem<String>(
              value: value,
              child: new Text(value),
              );}).toList(),
              onChanged: (value) {
                  setState(() { dropdownValue=value;});
              },
          )),

答案 8 :(得分:0)

我使用了一个技巧。所选项目作为列表中的第一个索引项。因此,每次更改项目时从列表中删除项目将项目重新插入为列表中的第一项列表。请参考以下代码。这里我使用 Object 作为下拉项,我将小部件作为提取函数使用。并且在调用 dropDownButton 函数之前 make

//项目列表如下

 List<LeaveType> items = [
 (id=1,name="Sick"),
 (id=2,name="Paid")
 ]

selectedLeave = null;

Row leaveTypeDropDown(StateSetter setCustomState, List<LeaveType> items) {
    if(selectedLeave != null){
      items.remove(selectedLeave);
      items.insert(0, selectedLeave);
    }
    return Row(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children : [
              text("Select Leave Type",textSize: 15),
              Padding(padding: const EdgeInsets.all(5)),
              Expanded(
                child: Container(
                  padding: const EdgeInsets.only(left: 10.0, right: 10.0),
                  decoration: BoxDecoration(
                    border: Border.all(color: Colors.black,width: 1),
                    borderRadius: const BorderRadius.all(Radius.circular(10.0)),
                  ),
                  child: DropdownButtonHideUnderline(
                    child: DropdownButton<LeaveType>(
                      isExpanded: true,
                      //initial value 
                      value: selectedLeave != null ? items[0] : null,
                      icon: const Icon(Icons.arrow_downward),
                      iconSize: 24,
                      elevation: 16,
                      hint: text("Leave Type"),
                      style: const TextStyle(
                          color: Colors.black
                      ),
                      onChanged: (LeaveType  value) {
                        setCustomState(() {
                          selectedLeave = value;
                          items.remove(selectedLeave);
                          items.insert(0, selectedLeave);
                        });
                      },
                      items: items
                          .map((leave) {
                        return  new DropdownMenuItem<LeaveType>(
                          value: leave,
                          child: text(leave.name),
                        );
                      }).toList(),
                    ),
                  ),
                ),
              ),
            ]
        );
  }

答案 9 :(得分:0)

我改成下面这样就解决了:

初始代码:

List<GamesModel> users = <GamesModel>[
  new GamesModel(1,"Option1"),
  new GamesModel(2,"Option2"),

];
return users;

更改代码:

List<GamesModel> users = <GamesModel>[
      const GamesModel(1,"Option1"),
      const GamesModel(2,"Option2"),
];
return users;

如果有人想要我可以把整个代码

答案 10 :(得分:0)

          DropdownButton<String>(
            iconEnabledColor: Colors.cyan.withOpacity(.6),
            isExpanded: true,
            itemHeight: 50,
            iconSize: 30,
            hint: Text("Choose Province"),
            items: _provinces
                .map((e) => DropdownMenuItem(
              child: Text(e),
              value: e,
            ))
                .toList(),
            value: _Province,
            onChanged: (String? value) async{
              final respnose=await FirebaseFirestore.instance.collection('city').where('provinceName',isEqualTo: value).get();
              _city=[];
              for(var item in respnose.docs){
                print(item.data());
                _city.add(item.data()['name']);
              }
              
              print(_Province);
              setState(() {
                _city=_city;
                _Province = value;
              });
            },
          ),
          SizedBox(height: 20,),

          DropdownButton<String>(
            iconEnabledColor: Colors.cyan.withOpacity(.6),
            isExpanded: true,
            itemHeight: 50,
            iconSize: 30,
            hint: Text("Choose City"),
            items:_city
                .map((e) => DropdownMenuItem(
              child: Text(e),
              value: e,
            ))
                .toList(),
            value: _City,
            onChanged: (String? value) async{
              setState(() {
                _town=[];
                _Town=null;
              });
              print(_town);
              final respnose=await FirebaseFirestore.instance.collection('town').where('cityName',isEqualTo: value).get();
              print(respnose.docs);


              for(var item in respnose.docs){
                print(item.data());
                _town.add(item.data()['name']);
              }
              print(_town);
              print(_City);
              setState(() {

                _City = value;
                _town=_town;
              });
            },
          ),
          SizedBox(height: 20,),

如果(真) 下拉按钮( iconEnabledColor: Colors.cyan.withOpacity(.6), isExpanded: 真, 项目高度:50, 图标大小:30, 提示:文本(“选择城镇”), 项目:_town .map((e) => DropdownMenuItem( 孩子:文本(e), 值:e, ) ) .toList(), 值:_Town, onChanged:(字符串?值)异步{ 打印(_镇); 设置状态((){ _Town = 价值; });

答案 11 :(得分:0)

如果您忘记为下拉菜单项指定值,也会发生此错误。 ==== 作品 ====

<String>['A', 'B', 'C'].map<DropdownMenuItem<String>>((vehicle) {
        print("vehicle is $vehicle");
        print("vehicle is equal ${vehicle == x.value}");
        return DropdownMenuItem<String>(
          value: vehicle,
          child: Text(
            // vehicle.vehicleInfo!.vehicleType!,
            vehicle,
            style: TextStyle(
              color: Colors.grey[600],
            ),
          ),
        );
      }).toList(),

==== 不起作用 ====

<String>['A', 'B', 'C'].map<DropdownMenuItem<String>>((vehicle) {
        return DropdownMenuItem<String>(
          child: Text(
            vehicle,
            style: TextStyle(
              color: Colors.grey[600],
            ),
          ),
        );
      }).toList(),