Flutter 动画合集
animations
AnimatedList
Details
dart
/// Flutter code sample for AnimatedList
// This sample application uses an [AnimatedList] to create an effect when
// items are removed or added to the list.
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
class AnimatedListSample extends StatefulWidget {
const AnimatedListSample({Key? key}) : super(key: key);
@override
State<AnimatedListSample> createState() => _AnimatedListSampleState();
}
class _AnimatedListSampleState extends State<AnimatedListSample> {
final GlobalKey<AnimatedListState> _listKey = GlobalKey<AnimatedListState>();
late ListModel<int> _list;
late int _nextItem;
@override
void initState() {
super.initState();
_list = ListModel<int>(
listKey: _listKey,
initialItems: <int>[0, 1, 2],
removedItemBuilder: _buildRemovedItem,
);
_nextItem = 3;
}
// Used to build an item after it has been removed from the list. This
// method is needed because a removed item remains visible until its
// animation has completed (even though it's gone as far this ListModel is
// concerned). The widget will be used by the
// [AnimatedListState.removeItem] method's
// [AnimatedListRemovedItemBuilder] parameter.
Widget _buildRemovedItem(
int item, BuildContext context, Animation<double> animation) {
return ListItem(
animation: animation,
item: item,
onRemove: _remove,
);
}
// Insert the "next item" into the list model.
void _insert() {
final int index = _list.length;
_list.insert(index, _nextItem++);
}
// Remove the selected item from the list model.
void _remove(item) {
if (item != null) {
_list.removeAt(_list.indexOf(item!));
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('AnimatedList'),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.add),
onPressed: _insert,
tooltip: '添加',
),
],
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: AnimatedList(
key: _listKey,
initialItemCount: _list.length,
itemBuilder: (context, index, animation) {
return FadeTransition(
opacity: animation,
child: ListItem(
onRemove: _remove,
animation: animation,
item: _list[index],
),
);
},
),
),
);
}
}
typedef RemovedItemBuilder<T> = Widget Function(
T item, BuildContext context, Animation<double> animation);
/// Keeps a Dart [List] in sync with an [AnimatedList].
///
/// The [insert] and [removeAt] methods apply to both the internal list and
/// the animated list that belongs to [listKey].
///
/// This class only exposes as much of the Dart List API as is needed by the
/// sample app. More list methods are easily added, however methods that
/// mutate the list must make the same changes to the animated list in terms
/// of [AnimatedListState.insertItem] and [AnimatedList.removeItem].
class ListModel<E> {
ListModel({
required this.listKey,
required this.removedItemBuilder,
Iterable<E>? initialItems,
}) : _items = List<E>.from(initialItems ?? <E>[]);
final GlobalKey<AnimatedListState> listKey;
final RemovedItemBuilder<E> removedItemBuilder;
final List<E> _items;
AnimatedListState? get _animatedList => listKey.currentState;
void insert(int index, E item) {
_items.insert(index, item);
_animatedList!.insertItem(index);
}
E removeAt(int index) {
final E removedItem = _items.removeAt(index);
if (removedItem != null) {
_animatedList!.removeItem(
index,
(BuildContext context, Animation<double> animation) {
return removedItemBuilder(removedItem, context, animation);
},
);
}
return removedItem;
}
int get length => _items.length;
E operator [](int index) => _items[index];
int indexOf(E item) => _items.indexOf(item);
}
/// Displays its integer item as 'item N' on a Card whose color is based on
/// the item's value.
///
/// The text is displayed in bright green if [selected] is
/// true. This widget's height is based on the [animation] parameter, it
/// varies from 0 to 128 as the animation varies from 0.0 to 1.0.
class ListItem extends StatelessWidget {
const ListItem({
Key? key,
required this.onRemove,
required this.animation,
required this.item,
}) : super(key: key);
final Animation<double> animation;
final ValueChanged onRemove;
final int item;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(2.0),
child: FadeTransition(
// axis: Axis.vertical,
// sizeFactor: animation,
opacity: animation,
child: Container(
child: Row(children: [
Expanded(
child: Text(
'Item $item',
style: TextStyle(
color: Colors.blue,
),
),
),
IconButton(
onPressed: () {
onRemove(this.item);
},
icon: Icon(Icons.delete_forever_rounded, color: Colors.grey),
),
]),
),
),
);
}
}