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

Abd*_*che 30 dart drop-down-menu flutter dropdownbutton flutter-futurebuilder

我正在尝试在 Flutter 中创建一个下拉按钮。我从我的数据库中获取一个列表,然后我将列表传递给我的dropdownButton 所有工作,数据按预期显示,但是当我从中选择一个元素时,我收到此错误:

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'
Run Code Online (Sandbox Code Playgroud)

我尝试将DropdownButton 值设置为 null它可以工作,但随后我看不到所选元素

这是我的代码:

FutureBuilder<List<Tag>>(
    future: _tagDatabaseHelper.getTagList(),
    builder: (BuildContext context, AsyncSnapshot<List<Tag>> snapshot) {
      if (!snapshot.hasData) {
        return Center(
          child: CircularProgressIndicator(),
        );
      }
      return ListView(
        children: <Widget>[
          SizedBox(
            height: MediaQuery.of(context).size.height * 0.2,
          ),
          Container(
            margin: EdgeInsets.symmetric(
                horizontal: MediaQuery.of(context).size.width * 0.07),
            child: Theme(
              data: ThemeData(canvasColor: Color(0xFF525A71)),
              child: DropdownButton<Tag>(
                value: _selectedTag,
                isExpanded: true,
                icon: Icon(
                  Icons.arrow_drop_down,
                  size: 24,
                ),
                hint: Text(
                  "Select tags",
                  style: TextStyle(color: Color(0xFF9F9F9F)),
                ),
                onChanged: (value) {
                  setState(() {
                    _selectedTag = value;
                  });
                },
                items: snapshot.data.map((Tag tag) {
                  return DropdownMenuItem<Tag>(
                    value: tag,
                    child: Text(
                      tag.tagTitle,
                      style: TextStyle(color: Colors.white),
                    ),
                  );
                }).toList(),
                value: _selectedTag,
              ),
            ),
          ),
Run Code Online (Sandbox Code Playgroud)

我用futureBuilder从数据库中获得我的列表

sud*_*007 52

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

我的 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,
),
Run Code Online (Sandbox Code Playgroud)

错误

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

String _salutation = ""; //Notice the empty String.
Run Code Online (Sandbox Code Playgroud)

这是一个错误!

正如错误消息正确提到的那样,初始选择不应为 null 或为空。

'项目==空|| items.isEmpty || 值==空||

因此崩溃了:

崩溃消息

解决方案
使用一些默认值初始化值对象。请注意,该值应该是您的集合中包含的值之一。如果不是,那么就会发生崩溃。

  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
Run Code Online (Sandbox Code Playgroud)

  • 请注意默认选择值应存在于数组中。 (10认同)
  • 另外,如果您使用自定义类,那么我们必须重写 == 运算符和哈希码才能正常工作或使用 Equatable 等包 (2认同)

Nut*_*uts 15

如果尝试使用类实例设置下拉列表的值,也可能会出现此错误;

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

要解决此覆盖运算符 ==:

class Tag{
 String name = "tag";

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

  @override
  int get hashCode => name.hashCode;
}
Run Code Online (Sandbox Code Playgroud)

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

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

  @override
  List<Object> get props => [name];
}
Run Code Online (Sandbox Code Playgroud)


mah*_*mnj 10

该线程上的一些答案肯定会帮助您解决问题。但是,如果您的 DropdownButton 正在处理自定义对象(在本例中为 Tag 类),那么首先要澄清为什么会出现此问题以及 DropdownButton 对您的期望。

为了给您提供有关该问题的一些背景知识,了解如何比较 dart 对象的两个实例非常重要。

如果您的 DropdownButton 正在处理 int、String、bool 等列表,您很可能不会看到上述错误。

这是因为您可以直接比较原始类型,并且会得到预期的结果。

例如

int x = 5;
int z = 10;
int y = 5;
String foo= 'hello';
String bar = 'hello; 

x == z; // false
x == y; // true
foo == bar; // true
Run Code Online (Sandbox Code Playgroud)

但是在处理自定义对象时,您必须格外小心,并且必须确保重写“==”运算符,以便 dart 知道如何比较自定义对象的实例。默认情况下,如果两个对象属于同一实例,则它们相等。

考虑标签类,

class Tag{
final String name;
final String code;

Tag({this.name,this.code});
}
Run Code Online (Sandbox Code Playgroud)
final tag1 = Tag(name:'foo', code: 'hello');
final tag2 = Tag(name:'foo', code: 'hello');
Tag tag3 = tag1;
Run Code Online (Sandbox Code Playgroud)

当您比较 tag3==tag1dart 时,它会按预期返回 true ,但是当您比较 时tag1 == tag2,dart 会返回false,因为两个对象不是同一实例。

因此,要解决这个问题,您需要重写运算==符 as 并修改您的 Tag 类,如下所示

class Tag{
final String name;
final String code;

Tag({this.name,this.code});

@override
  bool operator ==(Object other){
      return identical(this, other) ||
        (other.runtimeType == runtimeType &&
        other is Tag &&
        other.name == name &&
        other.code == code
   }
}
Run Code Online (Sandbox Code Playgroud)

现在当你比较时tag1 ==tag2它会返回 true。

这在官方文档中有记录https://dart.dev/guides/language/ effective-dart/design#equality

出现它预期的 DropdownButton 错误

  1. 项目不为空
  2. 项目不为空
  3. 值不为空
  4. 值在项目中只能出现一次

如果您使用自定义对象而不覆盖==运算符,第 4 点将会失败,因此您会收到上述错误。

太长了;

因此,要处理该错误,请确保上述 4 点满足并覆盖该==运算符,以便 dart 可以按照您的预期比较 Tag 类的实例。


小智 6

我的下拉列表的代码

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'];
Run Code Online (Sandbox Code Playgroud)

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


Ivá*_*oed 6

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

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

String dropdownValue = "Encajes";
Run Code Online (Sandbox Code Playgroud)
    items: categoriesString
    .map<DropdownMenuItem<String>>((String value) {
  return DropdownMenuItem<String>(
    value: value,
    child: Text(value),
  );
}).toList(),
Run Code Online (Sandbox Code Playgroud)