Flutter Widget组件库:AnimatedList
在构建复杂的用户界面时,动画经常被用来在视觉上提供反馈,改善用户体验。Flutter提供了一种称为AnimatedList的组件,它是一个可扩展的列表,具有在插入或删除条目时应用动画的功能,让我们在本文中更详细地探讨一下。
简介
AnimatedList 是动画版的List,可以轻松地为列表项的插入和移除应用动画效果。AnimatedList 使用动态状态作为其源,它是在其状态发生更改(例如:item添加或删除)时负责管理动画的集合。
属性和方法
重要属性:
key
:用来访问AnimatedList
的状态(AnimatedListState
),并调用其方法来插入或删除条目itemBuilder
:一个函数,用于在给定的上下文和索引处构建列表中的项目,并启动动画。它返回一个带有动画的widget。initialItemCount
:初始时列表中的项目数量。
重要方法(AnimatedListState的方法):
insertItem
:在 AnimatedList 的特定索引处插入一个项目。需要指定该索引及动画的时长。removeItem
:从 AnimatedList 的特定索引处删除一个项目。
示例
以下给出了使用AnimatedList组件的一个基础示例:
import 'package:flutter/material.dart';
void main() {
runApp(const AnimatedListSample());
}
class AnimatedListSample extends StatefulWidget {
const AnimatedListSample({super.key});
@override
State<AnimatedListSample> createState() => _AnimatedListSampleState();
}
class _AnimatedListSampleState extends State<AnimatedListSample> {
final GlobalKey<AnimatedListState> _listKey = GlobalKey<AnimatedListState>();
late ListModel<int> _list;
int? _selectedItem;
late int
_nextItem; // 当用户按下` + `按钮时插入的下一个元素。
@override
void initState() {
super.initState();
_list = ListModel<int>(
listKey: _listKey,
initialItems: <int>[0, 1, 2],
removedItemBuilder: _buildRemovedItem,
);
_nextItem = 3;
}
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,
//这里没有手势检测器:我们不希望被删除的元素具有交互性。
);
}
// 将“next item”插入到list模型中
void _insert() {
final int index =
_selectedItem == null ? _list.length : _list.indexOf(_selectedItem!);
_list.insert(index, _nextItem++);
}
//从列表模型中删除选定的项目。
void _remove() {
if (_selectedItem != null) {
_list.removeAt(_list.indexOf(_selectedItem!));
setState(() {
_selectedItem = null;
});
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('AnimatedList'),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.add_circle),
onPressed: _insert,
tooltip: 'insert a new item',
),
IconButton(
icon: const Icon(Icons.remove_circle),
onPressed: _remove,
tooltip: 'remove the selected item',
),
],
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: AnimatedList(
key: _listKey,
initialItemCount: _list.length,
itemBuilder: _buildItem,
),
),
),
);
}
}
typedef RemovedItemBuilder<T> = Widget Function(
T item, BuildContext context, Animation<double> animation);
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);
}
class CardItem extends StatelessWidget {
const CardItem({
super.key,
this.onTap,
this.selected = false,
required this.animation,
required this.item,
}) : assert(item >= 0);
final Animation<double> animation;
final VoidCallback? onTap;
final int item;
final bool selected;
@override
Widget build(BuildContext context) {
TextStyle textStyle = Theme.of(context).textTheme.headlineMedium!;
if (selected) {
textStyle = textStyle.copyWith(color: Colors.lightGreenAccent[400]);
}
return Padding(
padding: const EdgeInsets.all(2.0),
child: SizeTransition(
sizeFactor: animation,
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: onTap,
child: SizedBox(
height: 80.0,
child: Card(
color: Colors.primaries[item % Colors.primaries.length],
child: Center(
child: Text('Item $item', style: textStyle),
),
),
),
),
),
);
}
}
这个例子创建了一个AnimatedList和添加、删除按钮。当用户点击添加按钮时,会向列表的底部添加一个新的元素,这个元素会有一个展开的动画效果。点击一个item然后点击删除按钮,改元素会有一个收起的动画效果。
注意事项
我们需要保证在使用AnimatedListState的
insertItem
和removeItem
方法时,不只是改变_AnimatedListState_,还要改变用于构建列表项目的数据源。不要忘记在删除项目时也使用删除动画。如果列表项在动画还没有完成的情况下就被删除,AnimatedList可能会出错。
动态列表AnimatedList是Flutter丰富动画库中的一个强大工具。只要正确使用,它就能轻松为你的应用创建出流畅、吸引人的动画效果,提升整体的用户体验。
- 0
- 0
-
赞助
微信支付宝 -
分享