从listView.builder删除项目始终删除最后一项
当我尝试删除项目时,每次最后一项都会被删除。在搜索解决方案后,我发现它使用已有的窗口小部件来使用,而解决方案是在小部件中添加键。
所以我添加了钥匙,但问题还没有消失。 最后一项仍然被删除。 波纹管,我试图表现出尽可能详细的情况。最后,您会看到,当我以索引(0)删除该项目时,它被调用,但索引(1)被从UI处置。但是在列表中,第一个项目被正确删除了。
这是listView.builder
ListView.builder(
primary: false,
shrinkWrap: true,
scrollDirection: Axis.vertical,
physics: const NeverScrollableScrollPhysics(),
itemCount: saleItems.length,
itemBuilder: (BuildContext context, int index) {
print('Value key: ${ValueKey(index)}');
return ProductItemWidget(
key: ValueKey(index),
itemContext: context,
mainItems: batches,
onDelete: () {
setState(() {
saleItems.remove(saleItems[index]);
print(
'deleted $index - value ${ValueKey(index)}');
print(saleItems);
});
},
onNewSaleItem: (newItem) {
setState(() {
saleItems[index] = newItem;
});
print(saleItems);
},
);
},
),
将新项目添加到列表
SizedBox(
key: _addButtonKey,
child: KFilledButton(
text: 'New Sale Item',
onPressed: () {
setState(() {
saleItems.add(newSaleItemModal);
});
scrollToAddButton();
},
),
),
该项目的实例和列表
NewSaleItemModal newSaleItemModal = NewSaleItemModal();
List<NewSaleItemModal> saleItems = [];
ProductItemwidget()页
这是构造函数
class ProductItemWidget extends StatefulWidget {
void Function() onDelete;
List<dynamic>? mainItems;
BuildContext? itemContext;
Function(NewSaleItemModal newSaleItem) onNewSaleItem;
ProductItemWidget({
Key? key,
required this.onDelete,
required this.onNewSaleItem,
this.mainItems,
this.itemContext,
}) : super(key: key);
@override
State<ProductItemWidget> createState() => _ProductItemWidgetState();
}
这些是状态
@override
void initState() {
super.initState();
print('Created with key: ${widget.key}');
}
@override
void didChangeDependencies() {
types = profileRepository.getConfigEnums(type: EnumType.discountType);
getAllProductNames();
super.didChangeDependencies();
}
@override
void dispose() {
super.dispose();
print('Disposed key: ${widget.key}');
selectedProductName = null;
selectedProduct = null;
selectedType = null;
_discountController.dispose();
_rateController.dispose();
_quantityController.dispose();
_unitController.dispose();
_amountController.dispose();
}
这是我添加键
的地方
@override
Widget build(BuildContext itemContext) {
return Form(
key: widget.key,
child: ..........
),
}
添加第一个项目后,在控制台...
I/flutter (17380): Value key: [<0>]
I/flutter (17380): Created with key: [<0>]
I/flutter (17380): [NewSaleItemModal(productId: 23, batchId: 88, rate: 35567, quantity: 1, unitId: 1, discount: 0, discountType: null, amount: 35567)]
添加第二项后,在控制台...
I/flutter (17380): Value key: [<1>]
I/flutter (17380): Created with key: [<1>]
I/flutter (17380): [NewSaleItemModal(productId: 23, batchId: 88, rate: 35567, quantity: 1, unitId: 1, discount: 0, discountType: null, amount: 35567), NewSaleItemModal(productId: 4, batchId: 69, rate: 1158, quantity: 1, unitId: 1, discount: 0, discountType: null, amount: 1158)]
当我删除第一个项目时,在控制台...
I/flutter (17380): deleted 0 - value [<0>]
I/flutter (17380): [NewSaleItemModal(productId: 4, batchId: 69, rate: 1158, quantity: 1, unitId: 1, discount: 0, discountType: null, amount: 1158)]
I/flutter (17380): Value key: [<0>]
I/flutter (17380): Disposed key: [<1>]
When I tried to remove an item, every time the last item get removed. After searching for solutions, I found out it works this way with stateful widgets, and the solution is to add keys in the widgets.
So I added keys but the problem isn't gone. The last item still gets removed.
Bellow, I tried to show the situation as detailed as possible. At the very last, you will see, when I remove the item at index(0) it gets called but index(1) gets disposed from the UI. But in the list, the 1st item got removed properly.
This is the ListView.builder
ListView.builder(
primary: false,
shrinkWrap: true,
scrollDirection: Axis.vertical,
physics: const NeverScrollableScrollPhysics(),
itemCount: saleItems.length,
itemBuilder: (BuildContext context, int index) {
print('Value key: ${ValueKey(index)}');
return ProductItemWidget(
key: ValueKey(index),
itemContext: context,
mainItems: batches,
onDelete: () {
setState(() {
saleItems.remove(saleItems[index]);
print(
'deleted $index - value ${ValueKey(index)}');
print(saleItems);
});
},
onNewSaleItem: (newItem) {
setState(() {
saleItems[index] = newItem;
});
print(saleItems);
},
);
},
),
Adding new items to the list
SizedBox(
key: _addButtonKey,
child: KFilledButton(
text: 'New Sale Item',
onPressed: () {
setState(() {
saleItems.add(newSaleItemModal);
});
scrollToAddButton();
},
),
),
Instance of the item and the list
NewSaleItemModal newSaleItemModal = NewSaleItemModal();
List<NewSaleItemModal> saleItems = [];
ProductItemWidget() page
This is the Constructor
class ProductItemWidget extends StatefulWidget {
void Function() onDelete;
List<dynamic>? mainItems;
BuildContext? itemContext;
Function(NewSaleItemModal newSaleItem) onNewSaleItem;
ProductItemWidget({
Key? key,
required this.onDelete,
required this.onNewSaleItem,
this.mainItems,
this.itemContext,
}) : super(key: key);
@override
State<ProductItemWidget> createState() => _ProductItemWidgetState();
}
These are the states
@override
void initState() {
super.initState();
print('Created with key: ${widget.key}');
}
@override
void didChangeDependencies() {
types = profileRepository.getConfigEnums(type: EnumType.discountType);
getAllProductNames();
super.didChangeDependencies();
}
@override
void dispose() {
super.dispose();
print('Disposed key: ${widget.key}');
selectedProductName = null;
selectedProduct = null;
selectedType = null;
_discountController.dispose();
_rateController.dispose();
_quantityController.dispose();
_unitController.dispose();
_amountController.dispose();
}
This is the where I added the key
@override
Widget build(BuildContext itemContext) {
return Form(
key: widget.key,
child: ..........
),
}
After adding first item, in console...
I/flutter (17380): Value key: [<0>]
I/flutter (17380): Created with key: [<0>]
I/flutter (17380): [NewSaleItemModal(productId: 23, batchId: 88, rate: 35567, quantity: 1, unitId: 1, discount: 0, discountType: null, amount: 35567)]
After adding second item, in console...
I/flutter (17380): Value key: [<1>]
I/flutter (17380): Created with key: [<1>]
I/flutter (17380): [NewSaleItemModal(productId: 23, batchId: 88, rate: 35567, quantity: 1, unitId: 1, discount: 0, discountType: null, amount: 35567), NewSaleItemModal(productId: 4, batchId: 69, rate: 1158, quantity: 1, unitId: 1, discount: 0, discountType: null, amount: 1158)]
Here is the video deleting the first item
When i delete the first item, in console...
I/flutter (17380): deleted 0 - value [<0>]
I/flutter (17380): [NewSaleItemModal(productId: 4, batchId: 69, rate: 1158, quantity: 1, unitId: 1, discount: 0, discountType: null, amount: 1158)]
I/flutter (17380): Value key: [<0>]
I/flutter (17380): Disposed key: [<1>]
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
嗯,尝试使用删除位置来识别要删除的项目
hmm try using removeWhere to identify which item to be remove
只需使用
unique key()
而不是valuekey(index)
它似乎已经为我解决了问题。
Just use
UniqueKey()
instead ofValueKey(index)
It seems to have solved the problem for me.
我在两个不同的项目中也遇到了同样的问题,有时甚至应用了一个“解决方法”解决方案,例如
可见性(可见:!_isdeleted,Child:myListViewItem(...)
,但我总是最终出现采用相同的方法:管理库,例如scopedmodel,redux或bloc
使用状态
数字框等。
I also had the same problem in two my different projects, and sometimes even applied a "workaround" solution, like
Visibility(visible: !_isDeleted, child: MyListViewItem(...)
but I always ended up with the same approach:Use state management libraries. E.g. ScopedModel, Redux or Bloc. This appeared to be the only correct way for me.
In a few words:
model.removeItemAt(i)
. All listView items will be rebuilt properlyTextEditingController
s for all text fields and update the model each time user changes the textI hope it will help.