【问题标题】:Either zero or 2 or more [DropdownMenuItem]s were detected with the same value检测到 0 个或 2 个或多个 [DropdownMenuItem] 具有相同的值
【发布时间】:2020-05-12 11:31:36
【问题描述】:

我是 Flutter 的新手,但我正在尝试创建一个 DropdownButtonFormField,但它不起作用。我收到一条错误消息,提示我有重复值。有趣的是,我没有包含重复值的列表。我在 SO 上发现了一个类似的问题,解决方案说用一个值启动字符串,并且用户正在复制一个列表项,但是我对另一个列表有类似的解决方案,它似乎工作正常。我无法弄清楚为什么它在这里不起作用。非常感谢任何帮助。

错误信息:

There should be exactly one item with [DropdownButton]'s value: 0. 
Either zero or 2 or more [DropdownMenuItem]s were detected with the same value
'package:flutter/src/material/dropdown.dart':
Failed assertion: line 1411 pos 15: 'items == null || items.isEmpty || value == null ||
              items.where((DropdownMenuItem<T> item) {
                return item.value == value;
              }).length == 1'
The relevant error-causing widget was: 
  StreamBuilder<UserProfile>

ProfileForm 类:

final List<String> accountType = ['Educator', 'School Administrator', 'Parent'];

  String _currentAccountType;

  @override
  Widget build(BuildContext context) {
    final user = Provider.of<User>(context);
    return StreamBuilder<UserProfile>(
        stream: DatabaseService(uid: user.uid).userProfileData,
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            UserProfile userProfileData = snapshot.data;
            return Form(
              key: _formKey,
              child: Column(
                children: <Widget>[
                  SizedBox(height: 20.0),
                  DropdownButtonFormField(
                    decoration: textInputDecoration,
                    value: _currentAccountType ?? userProfileData.accountType,
                    items: accountType.map((accountType) {
                      return DropdownMenuItem(
                        value: accountType,
                        child: Text(accountType),
                      );
                    }).toList(),
                    onChanged: (val) {
                      setState(() {
                        _currentAccountType = val;
                      });
                    },
                  ),

数据库类

class DatabaseService {
  final String uid;
  DatabaseService({this.uid});

  final CollectionReference userProfileCollection =
      Firestore.instance.collection('user_profile');

  Future updateUserProfile(
      String accountType,
      String birthDate,
      String courseName,
      String dateJoined,
      String email,
      String firstName,
      String lastName,
      String schoolName,
      String title) async {
    return await userProfileCollection.document(uid).setData({
      'accountType': accountType,
      'birthDate': birthDate,
      'courseName': courseName,
      'dateJoined': dateJoined,
      'email': email,
      'firstName': firstName,
      'lastName': lastName,
      'schoolName': schoolName,
      'title': title,
    });
  }

  //User Profile from snapshot
  List<Profile> _userProfileListFromSnapshot(QuerySnapshot snapshot) {
    return snapshot.documents.map((doc) {
      return Profile(
        accountType: doc.data['accountType'] ?? '',
        birthDate: doc.data['birthDate'] ?? '',
        courseName: doc.data['courseName'] ?? '',
        dateJoined: doc.data['dateJoined'] ?? '',
        email: doc.data['email'] ?? '',
        firstName: doc.data['firstName'] ?? '',
        lastName: doc.data['lastName'] ?? '',
        schoolName: doc.data['schoolName'] ?? '',
        title: doc.data['title'] ?? '',
      );
    }).toList();
  }

  UserProfile _userProfileFromSnapshot(DocumentSnapshot snapshot) {
    return UserProfile(
      uid: uid,
      accountType: snapshot.data['accountType'],
      birthDate: snapshot.data['birthDate'],
      courseName: snapshot.data['courseName'],
      dateJoined: snapshot.data['dateJoined'],
      email: snapshot.data['email'],
      firstName: snapshot.data['firstName'],
      lastName: snapshot.data['lastName'],
      schoolName: snapshot.data['schoolName'],
      title: snapshot.data['title'],
    );
  }

  Stream<List<Profile>> get userProfile {
    return userProfileCollection.snapshots().map(_userProfileListFromSnapshot);
  }

  Stream<UserProfile> get userProfileData {
    return userProfileCollection
        .document(uid)
        .snapshots()
        .map(_userProfileFromSnapshot);
  }
}

【问题讨论】:

    标签: firebase flutter dart google-cloud-firestore


    【解决方案1】:

    userProfileData.accountType 为“0”,而不是“教育者”、“学校管理员”或“家长”。

    成功:值必须在 items.value 中

     final List<String> accountType = ['Educator', 'School Administrator', 'Parent'];
    
     DropdownButtonFormField(
                        decoration: textInputDecoration,
                        value: accountType[0],
                        items: accountType.map((accountType) {
                          return DropdownMenuItem(
                            value: accountType,
                            child: Text(accountType),
                          );
                        }).toList(),
                        onChanged: (val) {
                          setState(() {
                            _currentAccountType = val;
                          });
                        },
                      ),
    
    

    失败:应该只有一项具有[DropdownButton]的值:哈哈哈

     final List<String> accountType = ['Educator', 'School Administrator', 'Parent'];
    
     DropdownButtonFormField(
                        decoration: textInputDecoration,
                        value: 'hahaha',
                        items: accountType.map((accountType) {
                          return DropdownMenuItem(
                            value: accountType,
                            child: Text(accountType),
                          );
                        }).toList(),
                        onChanged: (val) {
                          setState(() {
                            _currentAccountType = val;
                          });
                        },
                      ),
    

    【讨论】:

    • 谢谢库!这是一个很容易解决的问题!
    • 确实是@Part_Time_Nerd。
    • @Kahou 得到同样的错误,但没有用这个解决方案修复。
    • 使用动态获取数据此解决方案会出错
    【解决方案2】:

    就我而言,以下更改解决了错误:

    错误场景:

    var itemList=['Alpha','Beta','Cat'];
    var itemSelected='Zebra';
    

    工作场景:

    var itemList=['Alpha','Beta','Cat'];
    var itemSelected='Cat'; //Can be Alpha, Beta or Cat but not any other value
    

    下拉小部件代码:

    DropdownButton<String>(
                        items: itemList.map((String singleItem){
                              return DropdownMenuItem<String>(
                                value: singleItem,
                                child:Text(singleItem)
                              );
                        }).toList(),
    
                        onChanged: (String itemChosen){
                          setState(() {
                            this.itemSelected=itemChosen;
                          });
                        },
                       value:itemSelected ,
    
                      ),
    

    让“itemSelected”变量值与列表中的元素之一相同解决了我的问题。

    【讨论】:

      【解决方案3】:

      我也遇到过这种情况,但是没有办法让你帮我看看错误码在哪里?

      var dataLv2 = new List<DropdownMenuItem<String>>();
      var dataLv3 = new List<DropdownMenuItem<String>>();
      
      Widget widgetLoaiViPham() {
          return StreamBuilder(
            initialData: "KHONG",
            stream: widget.bloc.subject_ketluan_cmis_loai_vipham_stream,
            builder: (context, snapshot) {
              return DropdownButtonFormField(
                value: snapshot.data,
                items: getDropDownMenuLv1(),
                decoration: InputDecoration(labelText: "Loại vi phạm"),
                onChanged: (newVal) {
                  dataLv2 = defaultVal2(newVal);
                  var tempVal2 = dataLv2.length > 0 ? dataLv2.first.value : null;
                  dataLv3 = defaultVal3(tempVal2);
                  var tempVal3 = dataLv3.length > 0 ? dataLv3.first.value : null;
      
                  widget.bloc.subject_ketluan_cmis_loai_vipham_sink.add(newVal);
                  widget.bloc.subject_ketluan_cmis_loai_kiemtra_sink.add(tempVal2);
                  widget.bloc.subject_ketluan_cmis_loai_xuly_sink.add(tempVal3);
                },
              );
            },
          );
      }
      
      Widget widgetLoaiKiemTra() {
          return StreamBuilder(
            initialData: null,
            stream: widget.bloc.subject_ketluan_cmis_loai_kiemtra_stream,
            builder: (context, snapshot) {
              return DropdownButtonFormField(
                value: null,
                items: dataLv2,
                decoration: InputDecoration(labelText: "Loại kiểm tra"),
                onChanged: (newVal) {
                  dataLv3 = defaultVal3(newVal);
                  var tempVal3 = dataLv3.length > 0 ? dataLv3.first.value : null;
      
                  widget.bloc.subject_ketluan_cmis_loai_kiemtra_sink.add(newVal);
                  widget.bloc.subject_ketluan_cmis_loai_xuly_sink.add(tempVal3);
                },
              );
            },
          );
      }
      

      更改widgetLoaiViPham时,widgetLoaiKiemTra的数据会根据一切正常而变化,但是当我更改widgetLoaiKiemTra然后我继续更改widgetLoaiViPham时,会出现错误。

      虽然调试,但是widgetLoaiKiemTra的值和项匹配

      【讨论】:

        【解决方案4】:

        同时使用 'hint:' 和 'value:' 时似乎有些冲突。 我的方法是在 Widget 的 State 中添加一个全局 _selected:

        bool _selected;
        

        然后在 DropdownButton 本身中:

        value: _selected ? _userChoice: null,
        

        通过这种方式,一旦设置了项目值,您就可以实际使用它们。

        这是取自一些培训代码的完整示例(请原谅愚蠢;)

        class FavoriteCity extends StatefulWidget {
          @override
          State<StatefulWidget> createState() {
            return _FavoriteCityState();
          }
        }
        
        class _FavoriteCityState extends State<FavoriteCity> {
          String nameCity = '';
          String _loveLevel = '';
          bool _selected = false;
          var _howMuchLoved = ['A little', 'So so', 'Quite a bit', 'A lot', 'Greatly'];
        
          @override
          Widget build(BuildContext context) {
            print('Widget Built');
            return Scaffold(
              appBar: AppBar(
                title: Text('Favorite city app'),
                elevation: 8.0,
              ),
              body: Container(
                margin: EdgeInsets.all(20.0),
                child: Column(
                  children: <Widget>[
                    TextField(
                      onSubmitted: (String userInput) {
                        setState(() {
                          print('State rebuilt');
                          nameCity = userInput;
                        });
                      },
                    ),
                    DropdownButton<String>(
                      hint: Text('How much do you love the city?'),
                      items: _howMuchLoved.map((String myMenuItem) {
                        return DropdownMenuItem<String>(
                          value: myMenuItem,
                          child: Text(myMenuItem),
                        );
                      }).toList(),
                      onChanged: (String valueSelectedByUser) {
                        _dropDownItemSelected(valueSelectedByUser);
                      },
                      value: _selected ? _loveLevel : null,
                      isDense: true,
                    ),
                    Padding(
                      padding: EdgeInsets.all(20.0),
                      child: Text(
                        'Your favorite city is $nameCity ! \n ... and you love it $_loveLevel',
                        style: TextStyle(
                          fontSize: 20.0,
                          fontStyle: FontStyle.italic,
                        ),
                      ),
                    ),
                  ],
                ),
              ),
            );
          }
        
          void _dropDownItemSelected(String valueSelectedByUser) {
            setState(() {
              this._loveLevel = valueSelectedByUser;
              _selected = true;
            });
          }
        

        【讨论】:

        • 你能用一些代码解释一下吗?似乎比较不完整。我遇到了同样的问题,这个建议不能解决我的问题
        • 我添加了一个完整的示例并更正了我在评论中的一个错字,这使得该示例无用 - 抱歉 :)
        • 是的,它对我有用。只有当用户选择了一个选项时,这才会填充该值。
        • 这就像魔术一样。感谢您的回答
        【解决方案5】:

        在我的情况下:我的列表有 duplicated data 这向我显示了这个错误,我知道它在我的应用程序中一直重复,所以在显示下拉按钮之前我只是清除了我的列表并在将列表传递到下拉列表之前重新填充列表。如果发生这种类型的错误,也请交叉检查此解决方案。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2023-02-16
          • 2023-01-26
          • 2011-09-29
          • 2022-08-17
          • 2015-11-13
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多