我对Flutter下拉菜单有疑问。当我选择其中一项时,会引发错误:
引发了另一个异常:'package:flutter / src / material / dropdown.dart':失败的断言:第481行pos 15:'value == null || items.where(((DropdownMenuItem item)=> item.value == value).length == 1':不正确。
我正在搜索,人们告诉您此错误的产生是因为所选元素不属于原始列表,但经过一些调试后,我看到了它。我找不到此错误的根源,因此不胜感激。
这是我的代码
FeedCategory模型
import 'package:meta/meta.dart';
class FeedCategory {
static final dbId = "id";
static final dbName = "name";
int id;
String name;
FeedCategory({this.id, @required this.name});
FeedCategory.fromMap(Map<String, dynamic> map)
: this(
id: map[dbId],
name: map[dbName],
);
Map<String, dynamic> toMap() {
return {
dbId: id,
dbName: name,
};
}
@override
String toString() {
return 'FeedCategory{id: $id, name: $name}';
}
}
小部件
import 'package:app2date/repository/repository.dart';
import 'package:app2date/model/FeedSource.dart';
import 'package:app2date/model/FeedCategory.dart';
import 'package:app2date/util/ui.dart';
import 'package:flutter/material.dart';
class ManageFeedSource extends StatefulWidget {
ManageFeedSource({Key key, this.feedSource}) : super(key: key);
final FeedSource feedSource;
@override
_ManageFeedSource createState() => new _ManageFeedSource();
}
class _ManageFeedSource extends State<ManageFeedSource> {
FeedCategory _feedCategory;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('New Feed'),
),
body: new FutureBuilder(
future: Repository.get().getFeedCategories(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
List<FeedCategory> categoriesList = snapshot.data;
if (categoriesList != null) {
return new DropdownButton<FeedCategory>(
hint: Text('Choose category...'),
value: _feedCategory,
items: categoriesList.map((FeedCategory category) {
return DropdownMenuItem<FeedCategory>(
value: category,
child: Text(category.name),
);
}).toList(),
onChanged: (FeedCategory category) {
print('Selected: $category');
setState(() {
_feedCategory = category;
});
},
);
} else {
return Container(
decoration: new BoxDecoration(color: Colors.white),
);
}
},
),
);
}
@override
void initState() {
super.initState();
}
}
存储库getFeedCategories方法
Future<List<FeedCategory>> getFeedCategories() async {
return await database.getFeedCategories();
}
数据库getFeedCategories方法
Future<List<FeedCategory>> getFeedCategories() async {
var dbClient = await db;
var query = "SELECT * FROM $feedCategoryTableName;";
var result = await dbClient.rawQuery(query);
List<FeedCategory> feedCategories = [];
for (Map<String, dynamic> item in result) {
feedCategories.add(new FeedCategory.fromMap(item));
}
return feedCategories;
}
答案 0 :(得分:5)
我想我已经解决了您的问题。这源于您使用FutureBuilder的方式。
这是我想发生的事情
将来完成,并建立列表,并包含以下各项:
obj 123 ==> FeedCategory(Prueba)
,obj 345 ==> FeedCategory(Categories 2)
您从下拉菜单中选择了项,setState()被称为
您的_feedCategory现在等于obj 123 ==> FeedCategory(Prueba)
窗口小部件已重建。它再次调用getFeedCategories()
未来完成,构建列表并包含以下项目
obj 567 ==> FeedCategory(Prueba)
,obj 789 ==> FeedCategory(Categories 2)
items.where((DropdownMenuItem item) => item.value == value).length == 1
,但长度== 0,因为找不到obj 123 ==> FeedCategory(Prueba)
。有两种解决方案可以解决您的问题。一种方法是将equals operator添加到您的FeedCategory
类中,以比较类别和/或ID。
另一种方法是将futurebuilder中使用的Future与发生变化的部分分开-您可以通过将future保留为成员变量(可以在initState中实例化它)来实现,也可以通过将内置到其自己的有状态小部件中(在这种情况下,您可以使ManageFeedSource成为StatelessWidget)。我建议最后一个选择。
让我知道这是否不能解决您的问题,但是我很确定这就是它正在做的事情的原因。
答案 1 :(得分:1)
要完成rmtmckenzie answer,请在FeedCategory对象中输入以下代码:
bool operator ==(o) => o is FeedCategory && o.name == name;
int get hashCode => name.hashCode;
答案 2 :(得分:0)
当我使用下拉列表中实际未包含的值初始化下拉列表时出现此错误,该错误消息无法明确显示该值。