I am trying to have a list of card which contains a ListTile and an AnimatedContainer (containing a dynamic list) which will expand when the user clicks on the ListTile.
This is how the list looks initially: initial
When the user clicks on one, it will expand the animatedContainer like so: expanded
However, during the animation, this happens: errordemo
This is the error message from above gif: errorMessage
The error last for as long as the duration i have set for the AnimatedContainer. I can fix this issue by simply stating a static height on the AnimatedContainer, however, I need the AnimatedContainer to have dynamic height depending on how many items are in the ListView.
Below is my code snippet, any help would be greatly appreciated.
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:shop_shop/providers/orders_provider.dart';
class OrdersScreen extends StatelessWidget {
static const routeName = 'order';
@override
Widget build(BuildContext context) {
final ordersProvider = Provider.of<OrdersProvider>(context);
final List<OrderItem> orderList = ordersProvider.orderList;
return Scaffold(
appBar: AppBar(
title: Text('Order History'),
),
body: Column(
children: [
Expanded(
child: ListView.builder(
itemBuilder: (ctx, i) {
OrderItem order = orderList[i];
return OrderCard(order: order);
},
itemCount: orderList.length,
),
),
],
),
);
}
}
class OrderCard extends StatefulWidget {
final OrderItem order;
const OrderCard({required this.order});
@override
State<OrderCard> createState() => _OrderCardState();
}
class _OrderCardState extends State<OrderCard> {
bool isExpanded = false;
@override
Widget build(BuildContext context) {
return Card(
child: Column(
children: [
ListTile(
subtitle: Text(
'\$${widget.order.totalPrice.toStringAsFixed(2)}',
),
title: Text(
DateFormat.yMMMMEEEEd().format(widget.order.orderDate),
),
onTap: () {
setState(() {
isExpanded = !isExpanded;
});
},
),
AnimatedContainer(
duration: Duration(milliseconds: 500),
curve: Curves.easeOutBack,
padding: EdgeInsets.only(top: 10, right: 15, left: 15, bottom: 12),
height: isExpanded ? null : 0,
width: double.infinity,
color: Colors.grey[300],
child: ListView.builder(
shrinkWrap: true,
itemBuilder: (ctx, i) => Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(widget.order.orderList[i].title),
Text('x${widget.order.orderList[i].quantity}'),
Text(widget.order.orderList[i].price.toStringAsFixed(2)),
],
),
itemCount: widget.order.orderList.length,
),
),
],
),
);
}
}
CodePudding user response:
Remove the line width: double.infinity,
inside the AnimatedContainer
. It should automatically expand without defining it.
The AnimatedContainer
has a finite width and tries to animate to an infinite width. That's why you get an error. But after that the parent limits the infinite width to a finite one and the error disappears.
CodePudding user response:
I've found a work-around solution by manually calculating height based on the length of the list, this way i don't need shrinkWrap, like so (see property height in AnimatedContainer):
AnimatedContainer(
duration: Duration(milliseconds: 300),
curve: Curves.linearToEaseOut,
padding: EdgeInsets.only(top: 10, right: 15, left: 15, bottom: 10),
height: isExpanded
? widget.order.orderList.length * 17.5 20 // <==== dynamic height
: 0,
width: double.infinity,
color: Colors.grey[300],
child: ListView.builder(
itemBuilder: (ctx, i) => Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(widget.order.orderList[i].title),
Text('x${widget.order.orderList[i].quantity}'),
Text(widget.order.orderList[i].price.toStringAsFixed(2)),
],
),
itemCount: widget.order.orderList.length,
),
),
Please feel free to post another answer if you found a more proper way, thanks!