Reputation: 9343
I am trying the widgets.AnimatedGrid.1 mysample
of AnimatedGrid class documentation and I am always getting a RangeError (index): Invalid value: Not in inclusive range whenever I replace at runtime the late ListModel<int> _list
in _AnimatedGridSampleState
with a new shorter list.
Simply replacing the code of _insert
handler with:
void _insert() {
setState(() {
_list = ListModel<int>(
listKey: _gridKey,
initialItems: <int>[7, 6, 5],
removedItemBuilder: _buildRemovedItem,
);
});
}
then clicking on +
button will throw a RangeError
.
Since build()
in AnimatedGridSampleState
depends of _list
I was expecting that it will build a new AnimatedGrid
with the correct initialItemCount
and avoiding RangeError
:
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: ...,
body: Padding(
padding: const EdgeInsets.all(16.0),
child: AnimatedGrid(
key: _gridKey,
initialItemCount: _list.length,
itemBuilder: _buildItem,
),
),
),
);
}
Yet, the _buildItem(...)
it is still being called with the same indexes of the former longer _list
. Why?
You can try it by yourself running on the browser in the snippet container of AnimatedGrid page, replacing _insert()
code just like shown in the following print screens. You will not see the RangeError
but you will see that former items 4, 5, 6 remain on the AnimatedGrid
.
Upvotes: 2
Views: 499
Reputation: 9343
Solved this problem by setting a new GlobalKey<AnimatedGridState> _gridKey
on _insert
handler of the OP example, which is now:
void _insert() {
setState(() {
_gridKey = GlobalKey<AnimatedGridState>();
_list = ListModel<int>(
listKey: _gridKey,
initialItems: <int>[7, 6, 5],
removedItemBuilder: _buildRemovedItem,
);
});
}
Upvotes: 0
Reputation: 63549
To remove items takes Duration(milliseconds: 300)
. So setState try to rebuild the items meanwhile and cause the issue. In order to overcome this issue, I came up with removing one by one and then inserting item, created another two method on the ListModel
.
class ListModel<E> {
.....
void clear() {
for (int i = _items.length - 1; i >= 0; i--) {
removeAt(i);
}
}
void addAll(List<E> item) {
for (int i = 0; i < item.length; i++) {
insert(i, item[i]);
}
}
Now while you like to reset the item.
void _insert() async {
_list.clear();
/// delay to looks good; kDuration takes to remove item, therefore I am using Future method.
await Future.delayed(const Duration(milliseconds: 300));
setState(() {
_list.addAll(<int>[7, 6, 5]);
});
}
Upvotes: 0
Reputation: 1
it would be better if you could share the function responsible for removing the item but i can guess what might be the problem if you are getting this error when removing the last item in the list
if you are removing an item then you need to be careful about something first let's take a look at the removing function
E removeAt(int index) {
final E removedItem = _items.removeAt(index);
if (removedItem != null) {
_animatedGrid!.removeItem(
index,
(BuildContext context, Animation<double> animation) {
return removedItemBuilder(removedItem, context, animation);
},
);
}
return removedItem;
as you can see at the start of the function we are using the index to remove the item we want to remove and storing it in a new variable
then we are using it here
_animatedGrid!.removeItem(
index,
(BuildContext context, Animation<double> animation) {
return removedItemBuilder(removedItem, context, animation);
},);
as you can see we are using the item that we removed from the list because it will be displayed during the animation that's why we need the item but not the index and we can't use the index directly in this part cause we already removed the item from the list so if we used it like that
_animatedGrid!.removeItem(
index,
(BuildContext context, Animation<double> animation) {
return removedItemBuilder(_items[index], context, animation);
},
);
you will be getting a RangeError (index): Invalid value: Not in inclusive range because this item is already removed and so it's index is out of range
Upvotes: -1