AnimatedList is a stateful widget, and its corresponding state type is AnimatedListState.
The structure of AnimatedList is as follows:
const AnimatedList({
Key? key,
required Widget Function(BuildContext, int, Animation<double>) itemBuilder, // Data builder
int initialItemCount = 0, // Total length of initial data
Axis scrollDirection = Axis.vertical, // Scroll direction
bool reverse = false, // Whether to display from bottom to top
ScrollController? controller, // Scroll controller, optional, controls the scroll position of the list
bool? primary, // Whether to associate with the parent scroll
ScrollPhysics? physics, // How to respond to user actions
bool shrinkWrap = false,
EdgeInsetsGeometry? padding, // Padding
Clip clipBehavior = Clip.hardEdge,
})
There are two methods in the state to add and remove elements in the list:
Note that if the list is bound to a data source list, you cannot directly achieve the effect of updating the list by removing or adding elements. You also need to execute the following methods:
// Insert element
void insertItem(
int index,
{Duration duration = _kDuration}
)
// Remove element
void removeItem(
int index,
Widget Function(BuildContext, Animation<double>) builder, {
Duration duration = _kDuration,
})
When adding or removing, the specified animation will be displayed.
When using insertItem and removeItem, you usually need to use a globalKey, but the globalKey needs to specify the generic type in order to call the methods to add and remove list elements:
final globalKey = GlobalKey<AnimatedListState>();
To add an element, you only need to:
list.add("New data");
globalKey.currentState!.insertItem(list.length - 1);
Removing an element is more complicated because you need to display the animation when the element leaves and then delete the corresponding entry in the data source:
Usually, we need to create a
_buildItemmethod to dynamically create child elements. When executingremoveItem, first create an identical child element in the callback, fade it out using animation, and finally delete the data in the data array.
// Remove element
_delItem(index) {
globalKey.currentState!.removeItem(index, (context, animation) {
// Get the element to be removed and fade it out
var removeItem = _buildItem(index);
return FadeTransition(
// Execute animation
opacity: animation,
child: removeItem,
);
});
list.removeAt(index); // Delete data from the array
}
Complete code#
// AnimatedList
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
// Define a globalKey
final globalKey = GlobalKey<AnimatedListState>();
List<String> list = ["First data", "Second data"];
bool flag = true;
Widget _buildItem(index) {
return ListTile(
title: Text(list[index]),
trailing: IconButton(
icon: const Icon(Icons.delete),
onPressed: () {
// Execute deletion
_delItem(index);
},
),
);
}
// Remove element
_delItem(index) {
globalKey.currentState!.removeItem(index, (context, animation) {
// Get the element to be removed and fade it out
var removeItem = _buildItem(index);
list.removeAt(index); // Delete data from the array
return FadeTransition(
// Execute animation
opacity: animation,
child: removeItem,
);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("kano")),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.add),
// This will not work on AnimatedList by directly manipulating the list
onPressed: () {
// setState(() {
// list.add("New data");
// });
/// Use the insertItem method in AnimatedList
list.add("New data");
globalKey.currentState!.insertItem(list.length - 1);
},
),
// Animated list with animation
body: AnimatedList(
key: globalKey,
initialItemCount: list.length,
itemBuilder: (context, index, animation) {
// Fade transition opacity enters from 0 to 1 and exits in reverse
return FadeTransition(opacity: animation);
// Scale transition
// return ScaleTransition(scale: animation);
},
),
);
}
}