在 DropdownButton 中选择 Item 会导致 Flutter 抛出错误

Posted

技术标签:

【中文标题】在 DropdownButton 中选择 Item 会导致 Flutter 抛出错误【英文标题】:Selection of Item in DropdownButton causes Flutter to throw error 【发布时间】:2019-01-02 16:45:02 【问题描述】:

我目前正在尝试从 REST API 检索数据(标签)并使用该数据填充我可以成功执行的下拉菜单,但在选择项目后,我收到以下错误,根据 this 会表示“所选值不是值列表的成员”:

项目 == null ||值 == 空 || items.where((DropdownMenuItem item) => item.value == value).length == 1': 不正确。

这发生在下拉菜单显示我选择的项目之后。但是,这是不应该发生的错误,因为我已经完成了必要的日志记录以检查数据是否确实分配给了相关列表。谁能帮我解决这个问题?我已将其隔离为源自 DropdownButton 的onChanged 中的setState() 方法,但似乎无法理解为什么这会导致问题。任何帮助将不胜感激!

我的代码如下:

class _TodosByTagsHomePageState extends State<TodosByTagsHomePage> 
    Tag selectedTag;

    final Logger log = new Logger('TodosByTags');

    @override
    Widget build(BuildContext context) 
      return Scaffold(
          appBar: AppBar(
            title: Text("Second Screen"),
          ),
          body: ListView(
              children: <Widget>[
                FutureBuilder<List<Tag>> (
                    future: fetchTags(),
                    builder: (context, snapshot) 
                      if (snapshot.hasData) 
                        log.info("Tags are present");
                        _tagsList = snapshot.data;
                        return DropdownButton<Tag>(
                          value: selectedTag,
                          items: _tagsList.map((value) 
                            return new DropdownMenuItem<Tag>(
                              value: value,
                              child: Text(value.tagName),
                            );
                          ).toList(),
                          hint: Text("Select tag"),
                          onChanged: (Tag chosenTag) 
                            setState(() 
                              log.info("In set state");
                              selectedTag = chosenTag;
                              Scaffold.of(context).showSnackBar(new SnackBar(content: Text(selectedTag.tagName)));
                            );
                          ,
                        ) ;
                       else if (snapshot.hasError) 
                        return Text("$snapshot.error");
                      

                      return Container(width: 0.0, height: 0.0);
                    ),
              ])
      );
    

// Async method to retrieve data from REST API
      Future<List<Tag>> fetchTags() async 
        final response =
        await http.get(REST_API_URL);

        if (response.statusCode == 200) 
          // If the call to the server was successful, parse the JSON
          var result = compute(parseData, response.body);
          return result;
         else 
          // If that call was not successful, throw an error.
          throw Exception('Failed to load post');
        
      

      static List<Tag> parseData(String response) 
        final parsed = json.decode(response);

        return (parsed["data"] as List).map<Tag>((json) =>
        new Tag.fromJson(json)).toList();
      

      List<Tag> _tagsList = new List<Tag>();

    

// Model for Tag
    class Tag 
      final String tagName;
      final String id;
      final int v;

      Tag(this.id, this.tagName, this.v);

      factory Tag.fromJson(Map<String, dynamic> json) 
        return new Tag(
          id: json['_id'],
          tagName: json['tagName'],
          v: json['__v'],
        );
      
    

【问题讨论】:

【参考方案1】:

像这样更新你的代码 我认为在FutureBuilder 中调用setState 时调用fetchTags()fetchTags() 移动到initState() 一次调用的问题

class _TodosByTagsHomePageState extends State<TodosByTagsHomePage> 
      Tag selectedTag;
      Future<List<Tag>> _tags;
      @override
      void initState() 
         _tags = fetchTags();
        super.initState();
      

      @override
      Widget build(BuildContext context) 
        return Scaffold(
            appBar: AppBar(
              title: Text("Second Screen"),
            ),
            body: ListView(children: <Widget>[
              FutureBuilder<List<Tag>>(
                  future: _tags,
                  builder: (context, snapshot) 
                    if (snapshot.hasData) 
                      return DropdownButton<Tag>(
                        value: selectedTag,
                        items: snapshot.data.map((value) 
                          print(value);
                          return  DropdownMenuItem<Tag>(
                            value: value,
                            child: Text(value.tagName),
                          );
                        ).toList(),
                        hint: Text("Select tag"),
                        onChanged: (Tag chosenTag) 
                          setState(() 
                            selectedTag = chosenTag;
                          );
                        ,
                      );
                     else if (snapshot.hasError) 
                      return Text("$snapshot.error");
                    

                    return Container(width: 0.0, height: 0.0);
                  ),
            ]));
      

【讨论】:

以上是关于在 DropdownButton 中选择 Item 会导致 Flutter 抛出错误的主要内容,如果未能解决你的问题,请参考以下文章

Flutter - 如何在小部件测试中选择 DropdownButton 项

DropdownButton 选择调用 Flutter 中其他字段的 onValidate 函数

DropDownButton 不显示我选择的选项

从 DropdownItems 中选择值后,DropdownButton 值未更新。如何使用 selectedValue 更新默认值?

Flutter:按钮下方的 DropDownButton 项

如何像 Flutter 中的 Spinner 一样在 DropdownButton 下方打开 DropDown 对话框?