I am working on a project in which i am generating an order list. Whenever, i try to delete an item from list. It's throwing an exception of RangeError (index): Invalid value: Only valid value is 0: 1
.
However, it deletes that item on the same time. If there is range issue why is it deleting that item? Or when does this error generated? Another thing is How can I apply try/catch in specific widget?
Here is the code:
class OrderList extends StatefulWidget {
@override
_OrderListState createState() => _OrderListState();
}
class _OrderListState extends State<OrderList> {
CartList cart = CartList.instance;
final GlobalKey<AnimatedListState> _key = GlobalKey();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.red,
elevation: 0.0,
title: Text('Orders'),
centerTitle: true,
actions: <Widget>[
Padding(
padding: const EdgeInsets.all(16.0),
child: Badge(
child: Icon(Icons.shopping_cart, color: Colors.white, size: 40),
badgeContent: Text(
cart.listLength(),
style: TextStyle(color: Colors.white),
),
badgeColor: Colors.amber,
toAnimate: true,
animationType: BadgeAnimationType.fade,
),
),
],
),
body: AnimatedList(
key: _key,
initialItemCount: cart.list.length,
itemBuilder: (context, index, animation) {
return _buildItem(cart.list[index], animation, index);
},
),
);
}
Widget _buildItem(FoodItem list, Animation<double> animation, int index) {
return SizeTransition(
sizeFactor: animation,
child: Card(
elevation: 2,
child: ListTile(
leading: CircleAvatar(
backgroundImage: AssetImage('assets/${cart.list[index].img}'),
),
title: Text(cart.list[index].name),
subtitle: Text(
'${cart.list[index].quantity} x ${cart.list[index].price} = ${cart.list[index].quantity * cart.list[index].price}'),
trailing: IconButton(
icon: Icon(
Icons.delete,
color: Colors.red,
),
onPressed: (){
_removeItem(index);
setState(() {
});
},
),
),
),
);
}
void _removeItem(int index) {
FoodItem removeItem = cart.list.removeAt(index);
AnimatedListRemovedItemBuilder builder = (context, animation){
return _buildItem(removeItem, animation, index);
};
_key.currentState.removeItem(index, builder);
}
}
You can copy paste run full code below
The default insert/remove animation duration is Duration(milliseconds: 300)
You can wait like milliseconds: 350
onPressed: () async{
_removeItem(index);
await Future.delayed(Duration(milliseconds: 350), () {});
setState(() {
cart.list.removeAt(index);
});
},
full code
import 'package:flutter/material.dart';
class FoodItem {
String name;
String img;
int quantity;
double price;
FoodItem({this.name, this.img, this.quantity, this.price});
}
class CartList {
List<FoodItem> list = [
FoodItem(
name: "1",
img: "https://picsum.photos/250?image=9",
quantity: 1,
price: 10.0),
FoodItem(
name: "2",
img: "https://picsum.photos/250?image=10",
quantity: 2,
price: 20.0),
FoodItem(
name: "3",
img: "https://picsum.photos/250?image=11",
quantity: 3,
price: 30.0),
FoodItem(
name: "4",
img: "https://picsum.photos/250?image=12",
quantity: 4,
price: 40.0)
];
}
class OrderList extends StatefulWidget {
@override
_OrderListState createState() => _OrderListState();
}
class _OrderListState extends State<OrderList> {
CartList cart = CartList();
final GlobalKey<AnimatedListState> _key = GlobalKey();
@override
Widget build(BuildContext context) {
print(cart.list.length);
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.red,
elevation: 0.0,
title: Text('Orders'),
centerTitle: true,
),
body: cart.list.length == 0
? Container(child: Text("empty"))
: AnimatedList(
key: _key,
initialItemCount: cart.list.length,
itemBuilder: (context, index, animation) {
print(index);
return _buildItem(cart.list[index], animation, index);
},
),
);
}
Widget _buildItem(FoodItem list, Animation<double> animation, int index) {
return SizeTransition(
sizeFactor: animation,
child: Card(
elevation: 2,
child: ListTile(
leading: CircleAvatar(
backgroundImage: NetworkImage('${cart.list[index].img}'),
),
title: Text(cart.list[index].name),
subtitle: Text(
'${cart.list[index].quantity} x ${cart.list[index].price} = ${cart.list[index].quantity * cart.list[index].price}'),
trailing: IconButton(
icon: Icon(
Icons.delete,
color: Colors.red,
),
onPressed: () async{
_removeItem(index);
await Future.delayed(Duration(milliseconds: 350), () {});
setState(() {
cart.list.removeAt(index);
});
},
),
),
),
);
}
void _removeItem(int index) {
//FoodItem removeItem = cart.list.removeAt(index);
FoodItem removeItem = cart.list[index];
AnimatedListRemovedItemBuilder builder = (context, animation) {
return _buildItem(removeItem, animation, index);
};
_key.currentState.removeItem(index, builder);
//cart.list.removeAt(index);
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: OrderList(),
);
}
}