简介
AnimatedList “动画滚动容器”
- 一个滚动容器,可在插入或移除项目时为其设置动画
基本用法
AnimatedList
- AnimatedListState 可用于动态插入或删除项目。
- 下面示例展示效果:点击+号增加 card, 点击 card 保持激活状态,再点击-号,减少 card。
实例演示
import 'package:flutter/material.dart';
import 'package:flutter_go/widgets/components/List/AnimatedList/model.dart';
class AnimatedListFullDefault extends StatefulWidget {
AnimatedListFullDefault({Key key, this.parent}) : super(key: key);
final parent;
@override
_AnimatedListFullDefault createState() => _AnimatedListFullDefault();
}
/*
* AnimatedList 默认的实例,有状态
* */
class _AnimatedListFullDefault extends State<AnimatedListFullDefault> {
final GlobalKey<AnimatedListState> _listKey = GlobalKey<AnimatedListState>();
ListModel<int> _list;
int _selectedItem;
int _nextItem; // The next item inserted when the user presses the '+' button.
@override
void initState() {
super.initState();
if (widget.parent is State) {
widget.parent.animatedList = this; // 修改父级的对象引用
}
_list = ListModel<int>(
listKey: _listKey,
initialItems: <int>[0, 1, 2],
removedItemBuilder: _buildRemovedItem,
);
_nextItem = 3;
}
void insert() {
final int index = _selectedItem == null ? _list.length : _list.indexOf(_selectedItem);
_list.insert(index, _nextItem++);
}
// Remove the selected item from the list model.
void remove() {
if (_selectedItem != null) {
_list.removeAt(_list.indexOf(_selectedItem));
if(mounted) {
setState(() {
_selectedItem = null;
});
}
}
}
Widget _buildItem(BuildContext context, int index, Animation<double> animation) {
return CardItem(
animation: animation,
item: _list[index],
selected: _selectedItem == _list[index],
onTap: () {
setState(() {
_selectedItem = _selectedItem == _list[index] ? null : _list[index];
});
},
);
}
Widget _buildRemovedItem(int item, BuildContext context, Animation<double> animation) {
return CardItem(
animation: animation,
item: item,
selected: false,
// No gesture detector here: we don't want removed items to be interactive.
);
}
@override
Widget build(BuildContext context) {
return SizedBox(
height: 500.0,
child:AnimatedList(
//shrinkWrap: true,
key: _listKey,
initialItemCount: _list.length,
itemBuilder: _buildItem,
));
}
void methodA() {}
}
class CardItem extends StatelessWidget {
const CardItem({
Key key,
@required this.animation,
this.onTap,
@required this.item,
this.selected: false
}) : assert(animation != null),
assert(item != null && item >= 0),
assert(selected != null),
super(key: key);
final Animation<double> animation;
final VoidCallback onTap;
final int item;
final bool selected;
@override
Widget build(BuildContext context) {
TextStyle textStyle = Theme.of(context).textTheme.display1;
if (selected)
textStyle = textStyle.copyWith(color: Colors.lightGreenAccent[400]);
return Padding(
padding: const EdgeInsets.all(2.0),
child: SizeTransition(
axis: Axis.vertical,
sizeFactor: animation,
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: onTap,
child: SizedBox(
height: 128.0,
child: Card(
color: Colors.primaries[item % Colors.primaries.length],
child: Center(
child: Text('Item $item', style: textStyle),
),
),
),
),
),
);
}
}
model
import 'package:flutter/material.dart';
class ListModel<E> {
ListModel({
@required this.listKey,
@required this.removedItemBuilder,
Iterable<E> initialItems,
}) : assert(listKey != null),
assert(removedItemBuilder != null),
_items = List<E>.from(initialItems ?? <E>[]);
final GlobalKey<AnimatedListState> listKey;
final dynamic 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);
}