因此,我正在使用StaggeredGridView创建此应用程序,该应用程序是在线商店的商品目录,在这里我添加了一个功能,用于从列表中对商品进行排序,以便我可以按价格对商品进行排序或将其恢复为默认排序,但是我遇到一个问题,当我选择列表时,列表无法返回默认排序,这是代码:
class ItemCatalogState extends State<ItemCatalog>{
sortedBy sorted = sortedBy.init;
bool isInit = true;
var selectedList = [];
void sortItem(List<Item> initialList){
switch (sorted) {
case sortedBy.lowestPrice:
setState(() {
selectedList.sort((a,b){return a.price.compareTo(b.price);});
});
break;
case sortedBy.highestPrice:
setState(() {
selectedList.sort((a,b){return b.price.compareTo(a.price);});
});
break;
case sortedBy.init:
//NOT WORKING
setState(() {
selectedList = initialList;
});
break;
default:
}
}
@override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
List<Item> itemList = Provider.of<List<Item>>(context);
if(isInit&&itemList!=null){
selectedList = itemList.map((e) => Item(image: e.image,name: e.name,isReady: e.isReady,price: e.price,seller: e.seller)).toList();
isInit = false;
}
sortItem(itemList);
return Container(
child: DropdownButtonHideUnderline(
child: DropdownButton(
value: sorted,
items: [
DropdownMenuItem(
child: Text('Default',),
value: sortedBy.init,),
DropdownMenuItem(
child: Text('Lowest',),
value: sortedBy.lowestPrice,),
DropdownMenuItem(
child: Text('Highest'),
value: sortedBy.highestPrice,),
],
onChanged: (value){
setState(() {
sorted = value;
});
}),
),
),
Container(
decoration: BoxDecoration(
color: kGrayMainColor,
),
child: StaggeredGridView.countBuilder(
itemCount: selectedList!=null?selectedList.length:itemList.length,
crossAxisCount: 2,
itemBuilder: (context, index) {
Item currentItem = selectedList!=null?selectedList[index]:itemList[index];
return ItemTile(item: currentItem, size: size,);
},
),
),
),
]),]
);
}
当我单击默认下拉列表时,应该调用原始列表,但是没有任何更改,将列表复制到selectedList可能会出错吗?谢谢,关于我的其他不良代码实践的任何建议也值得赞赏,因为我仍在学习。
答案 0 :(得分:1)
在sortItems
内,您将selectedList
设置为等于initialList
。从那时起,两个变量现在都指向同一对象集合,这意味着您对一个对象执行的任何操作,对另一个对象也将执行的操作。并且由于您是通过提供程序获取集合的,所以这些更改还将影响所提供的原始列表。
代替直接分配,请再次复制initialList
,以使两个列表永远不会指向同一集合。
顺便说一句,有一种更简单的方法来创建列表副本:
selectedList = List.from(initialList);
另一方面,我假设sorted
的默认值为sortedBy.init
。这会使build
方法中的初始副本变得多余,因为sortItems
方法会立即覆盖selectedList
的值。相反,只需依靠sortItems
来生成列表,而不必担心初始化:
void sortItem(List<Item> initialList){
switch (sorted) {
case sortedBy.lowestPrice:
selectedList = List.from(initialList)
..sort((a,b) => a.price.compareTo(b.price));
break;
case sortedBy.highestPrice:
selectedList = List.from(initialList)
..sort((a,b) => b.price.compareTo(a.price));
break;
case sortedBy.init:
selectedList = List.from(initialList);
break;
}
setState(() {}); // Just call this once to reduce code duplication and verbosity
}
@override
Widget build(BuildContext context) {
...
List<Item> itemList = Provider.of<List<Item>>(context);
sortItems(itemList);
...
}
答案 1 :(得分:0)
这就是我要解决的方法(为简单起见,我将您的List<Item>
更改为List<String>
,但您的要旨是)
通过Provider将原始列表加载到_sortedList变量中(最初在didChangeDependencies中),并在需要再次使用原始列表时重复此操作。
(我的提供者返回了['aa', 'dd', 'cc']
,所以我也可以进入列表中的map():))
enum SortOrder { ascending, descending, original }
class _TestState extends State<Test> {
var _sortedList = List<String>();
@override
void didChangeDependencies() {
super.didChangeDependencies();
_loadOriginalList();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
RaisedButton(
child: Text('Ascending'),
onPressed: () => setState(() => _sortList(SortOrder.ascending)),
),
RaisedButton(
child: Text('Descending'),
onPressed: () => setState(() => _sortList(SortOrder.descending)),
),
RaisedButton(
child: Text('Original'),
onPressed: () => setState(() => _sortList(SortOrder.original)),
),
],
),
ListView.builder(
shrinkWrap: true,
itemCount: _sortedList.length,
itemBuilder: (context, index) => Center(
child: Text(_sortedList[index]),
),
),
],
),
);
}
void _sortList(SortOrder sortOrder) {
switch (sortOrder) {
case SortOrder.ascending:
_sortedList.sort();
break;
case SortOrder.descending:
_sortedList.sort();
_sortedList = _sortedList.reversed.toList();
break;
case SortOrder.original:
_loadOriginalList();
break;
}
}
void _loadOriginalList() {
final originalList = Provider.of<List<String>>(context, listen: false);
_sortedList.clear();
_sortedList.addAll(originalList.map((e) => e.substring(0, 1)));
}
}