在 AnimatedList 中添加或删除列表项时,有没有一种方法可以平滑地调整列表项的位置?
Is there a way to smoothly tween the position of list items when adding or removing from an AnimatedList?
我有一个 AnimatedList
,我可以很好地添加和删除项目。我的问题是,当我将一个项目添加到列表顶部时,它下面的项目会跳下来为它制作 space,而不是平滑过渡。
我发现 this answer 它提供了一种解决方案,可以在移除项目时平滑地动画化项目,但我无法使用相同的解决方案来插入项目。
这就是我目前所拥有的。当项目被添加到列表的顶部时,它下面的元素会平滑地移动。然而,新元素的缩放过渡也遵循这种转变。
class Foo extends StatefulWidget {
Foo({Key key}) : super(key: key);
final kDuration = const Duration(seconds: 1);
@override
_FooState createState() => _FooState();
}
class _FooState extends State<Foo> {
final _key = GlobalKey<AnimatedListState>();
List<Color> _items;
int _counter;
@override
void initState() {
super.initState();
_items = <Color>[];
_counter = 0;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Animated List Spike'),
),
body: AnimatedList(
key: _key,
initialItemCount: _items.length,
itemBuilder: (context, index, animation) {
return Stack(
children: [
// This transition creates the smooth shift-down effect.
SizeTransition(
sizeFactor: animation.drive(Tween(begin: 0, end: 1)),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 64,
color: Colors.transparent,
),
),
),
// This is the content we actually want to show.
Align(
alignment: Alignment.topCenter,
heightFactor: 0,
child: SlideTransition(
position: Tween(
begin: Offset(0, -0.5),
end: Offset(0, 0),
).animate(animation),
child: ScaleTransition(
scale: CurveTween(curve: Curves.easeOutBack)
.animate(animation),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
color: _items[index],
child: Container(height: 64),
),
),
),
),
),
],
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: addItem,
child: const Icon(Icons.add),
),
);
}
void addItem() {
_items.insert(0, Colors.primaries[_counter++ % Colors.primaries.length]);
_key.currentState.insertItem(0, duration: widget.kDuration);
}
}
有没有办法让元素平滑移动,然后然后让新元素缩放?
解决方案是使用 Interval
曲线。通过让一条曲线在 0.5
标记处结束,另一条曲线从那里开始,我能够使元素向下滑动,然后让我的新元素缩放。
CurveTween(
curve: Interval(
0.5, // Start halfway through the animation.
1.0, // Stop at the end of the animation.
curve: Curves.easeOutBack,
),
).animate(animation),
问题的完整解决方案:
itemBuilder: (context, index, animation) {
return Stack(
children: [
SizeTransition(
sizeFactor: animation.drive(
CurveTween(
curve: Interval(
0.0,
0.5,
curve: Curves.linear,
),
),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 64,
color: Colors.transparent,
),
),
),
Align(
alignment: Alignment.topCenter,
heightFactor: 0,
child: ScaleTransition(
scale: CurveTween(
curve: Interval(
0.5,
1.0,
curve: Curves.easeOutBack,
),
).animate(animation),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
color: _items[index],
child: Container(height: 64),
),
),
),
),
],
);
我有一个 AnimatedList
,我可以很好地添加和删除项目。我的问题是,当我将一个项目添加到列表顶部时,它下面的项目会跳下来为它制作 space,而不是平滑过渡。
我发现 this answer 它提供了一种解决方案,可以在移除项目时平滑地动画化项目,但我无法使用相同的解决方案来插入项目。
这就是我目前所拥有的。当项目被添加到列表的顶部时,它下面的元素会平滑地移动。然而,新元素的缩放过渡也遵循这种转变。
class Foo extends StatefulWidget {
Foo({Key key}) : super(key: key);
final kDuration = const Duration(seconds: 1);
@override
_FooState createState() => _FooState();
}
class _FooState extends State<Foo> {
final _key = GlobalKey<AnimatedListState>();
List<Color> _items;
int _counter;
@override
void initState() {
super.initState();
_items = <Color>[];
_counter = 0;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Animated List Spike'),
),
body: AnimatedList(
key: _key,
initialItemCount: _items.length,
itemBuilder: (context, index, animation) {
return Stack(
children: [
// This transition creates the smooth shift-down effect.
SizeTransition(
sizeFactor: animation.drive(Tween(begin: 0, end: 1)),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 64,
color: Colors.transparent,
),
),
),
// This is the content we actually want to show.
Align(
alignment: Alignment.topCenter,
heightFactor: 0,
child: SlideTransition(
position: Tween(
begin: Offset(0, -0.5),
end: Offset(0, 0),
).animate(animation),
child: ScaleTransition(
scale: CurveTween(curve: Curves.easeOutBack)
.animate(animation),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
color: _items[index],
child: Container(height: 64),
),
),
),
),
),
],
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: addItem,
child: const Icon(Icons.add),
),
);
}
void addItem() {
_items.insert(0, Colors.primaries[_counter++ % Colors.primaries.length]);
_key.currentState.insertItem(0, duration: widget.kDuration);
}
}
有没有办法让元素平滑移动,然后然后让新元素缩放?
解决方案是使用 Interval
曲线。通过让一条曲线在 0.5
标记处结束,另一条曲线从那里开始,我能够使元素向下滑动,然后让我的新元素缩放。
CurveTween(
curve: Interval(
0.5, // Start halfway through the animation.
1.0, // Stop at the end of the animation.
curve: Curves.easeOutBack,
),
).animate(animation),
问题的完整解决方案:
itemBuilder: (context, index, animation) {
return Stack(
children: [
SizeTransition(
sizeFactor: animation.drive(
CurveTween(
curve: Interval(
0.0,
0.5,
curve: Curves.linear,
),
),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 64,
color: Colors.transparent,
),
),
),
Align(
alignment: Alignment.topCenter,
heightFactor: 0,
child: ScaleTransition(
scale: CurveTween(
curve: Interval(
0.5,
1.0,
curve: Curves.easeOutBack,
),
).animate(animation),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
color: _items[index],
child: Container(height: 64),
),
),
),
),
],
);