Animation 颤振动画列表还是janky?
我目前在我的Flitter应用程序中使用了一个动画列表,并且对移除列表项的动画制作方式有问题Animation 颤振动画列表还是janky?,animation,flutter,dart,Animation,Flutter,Dart,我目前在我的Flitter应用程序中使用了一个动画列表,并且对移除列表项的动画制作方式有问题动画本身按预期工作,但一旦删除的项目完成动画,它就会消失,导致其他小部件跳入其位置。我原以为其他物品会转移到移除物品的位置 我尝试用ScaleTransition包装我的列表项,但没有帮助-其他列表项在完成动画之前仍然不会对删除的项作出反应 这有点违背了动画列表的目的,对吧?还是我做错了什么?关于AnimatedList的“本周小部件”视频清楚地显示,列表项通过改变其位置对新插入的项作出反应 这是我的密码
动画本身按预期工作,但一旦删除的项目完成动画,它就会消失,导致其他小部件跳入其位置。我原以为其他物品会转移到移除物品的位置 我尝试用
ScaleTransition
包装我的列表项,但没有帮助-其他列表项在完成动画之前仍然不会对删除的项作出反应
这有点违背了动画列表的目的,对吧?还是我做错了什么?关于AnimatedList的“本周小部件”视频清楚地显示,列表项通过改变其位置对新插入的项作出反应
这是我的密码:
@override
Widget build(BuildContext context) {
return AnimatedList(
padding: EdgeInsets.only(top: REGULAR_DIM,
bottom: REGULAR_DIM + kBottomNavigationBarHeight),
initialItemCount: data.length,
itemBuilder: (context, index, animation) {
return MyCustomWidget(
data: data[index],
animation: animation,
disabled: false
);
},
);
}
class MyCustomWidget extends AnimatedWidget {
final MyModel data;
final bool disabled;
MyCustomWidget({
@required this.data,
@required Animation<double> animation,
this.disabled = false
}) : super(listenable: animation);
Animation<double> get animation => listenable;
@override
Widget build(BuildContext context) {
final content = ... ;
return ScaleTransition(
scale: CurvedAnimation(
parent: animation,
curve: Interval(0, 0.25)
).drive(Tween(begin: 0, end: 1)),
child: FadeTransition(
opacity: animation,
child: SlideTransition(
position: animation.drive(
Tween(begin: Offset(-1, 0), end: Offset(0, 0))
.chain(CurveTween(curve: Curves.easeOutCubic))),
child: content,
),
),
);
}
}
关键是触发两个转换,一个是SlideTransition(),另一个是SizeTransition,以消除在删除项目时跳转 下面是一些示例代码
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(title: Text('Update AnimatedList data')),
body: BodyWidget(),
),
);
}
}
class BodyWidget extends StatefulWidget {
@override
BodyWidgetState createState() {
return new BodyWidgetState();
}
}
class BodyWidgetState extends State<BodyWidget>
with SingleTickerProviderStateMixin {
// the GlobalKey is needed to animate the list
final GlobalKey<AnimatedListState> _listKey = GlobalKey(); // backing data
List<String> _data = ['Horse', 'Cow', 'Camel', 'Sheep', 'Goat'];
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
SizedBox(
height: 400,
child: AnimatedList(
key: _listKey,
initialItemCount: _data.length,
itemBuilder: (context, index, animation) {
return _buildItem(
_data[index],
animation,
);
},
),
),
RaisedButton(
child: Text(
'Insert single item',
style: TextStyle(fontSize: 20),
),
onPressed: () {
_onButtonPress();
},
),
RaisedButton(
child: Text(
'Remove single item',
style: TextStyle(fontSize: 20),
),
onPressed: () {
_removeSingleItems();
},
),
],
);
}
Widget _buildItem(String item, Animation<double> animation, {direction: 0}) {
return (direction == 0)
? SizeTransition(
sizeFactor: animation,
child: Card(
color: Colors.amber,
child: ListTile(
title: Text(
item,
style: TextStyle(fontSize: 20),
),
),
),
)
: Stack(
children: [
SizeTransition(
sizeFactor: animation,
child: Card(
color: Colors.transparent,
child: ListTile(
title: Text(
item,
style: TextStyle(fontSize: 20),
),
),
),
),
Align(
alignment: Alignment.topCenter,
heightFactor: 0,
child: SlideTransition(
position: animation
.drive(Tween(begin: Offset(-1, 0), end: Offset(0, 0))),
child: Card(
color: Colors.red,
child: ListTile(
title: Text(
item,
style: TextStyle(fontSize: 20),
),
),
),
),
),
],
);
}
void _onButtonPress() {
_insertSingleItem();
}
void _insertSingleItem() {
String item = "Pig";
int insertIndex = 2;
_data.insert(insertIndex, item);
_listKey.currentState.insertItem(insertIndex);
}
void _removeSingleItems() {
int removeIndex = 2;
String removedItem = _data.removeAt(removeIndex);
// This builder is just so that the animation has something
// to work with before it disappears from view since the
// original has already been deleted.
AnimatedListRemovedItemBuilder builder = (context, animation) {
// A method to build the Card widget.
return _buildItem(removedItem, animation, direction: 1);
};
_listKey.currentState.removeItem(removeIndex, builder);
}
void _updateSingleItem() {
final newValue = 'I like sheep';
final index = 3;
setState(() {
_data[index] = newValue;
});
}
}
enter code here
导入“包装:颤振/材料.省道”;
void main(){
runApp(MyApp());
}
类MyApp扩展了无状态小部件{
@凌驾
小部件构建(构建上下文){
返回材料PP(
debugShowCheckedModeBanner:false,
家:脚手架(
appBar:appBar(标题:文本(“更新动画列表数据”),
body:BodyWidget(),
),
);
}
}
类BodyWidget扩展了StatefulWidget{
@凌驾
BodyWidgetState createState(){
返回新的BodyWidgetState();
}
}
类BodyWidgetState扩展了状态
使用SingleTickerProviderStateMixin{
//需要GlobalKey来设置列表的动画
final GlobalKey _listKey=GlobalKey();//支持数据
列表数据=[“马”、“牛”、“骆驼”、“羊”、“山羊”];
@凌驾
小部件构建(构建上下文){
返回列(
儿童:[
大小盒子(
身高:400,
子:动画列表(
键:_listKey,
initialItemCount:_data.length,
itemBuilder:(上下文、索引、动画){
返回_buildItem(
_数据[索引],
动画
);
},
),
),
升起的按钮(
子:文本(
“插入单个项目”,
样式:TextStyle(字体大小:20),
),
已按下:(){
_onButtonPress();
},
),
升起的按钮(
子:文本(
“删除单个项目”,
样式:TextStyle(字体大小:20),
),
已按下:(){
_删除singleitems();
},
),
],
);
}
小部件_buildItem(字符串项,动画,{方向:0}){
返回(方向==0)
?尺寸转换(
sizeFactor:动画,
孩子:卡片(
颜色:颜色。琥珀色,
孩子:ListTile(
标题:正文(
项目,,
样式:TextStyle(字体大小:20),
),
),
),
)
:堆栈(
儿童:[
尺寸转换(
sizeFactor:动画,
孩子:卡片(
颜色:颜色。透明,
孩子:ListTile(
标题:正文(
项目,,
样式:TextStyle(字体大小:20),
),
),
),
),
对齐(
对齐:alignment.topCenter,
高度系数:0,
子:幻灯片转换(
位置:动画
.drive(二者之间(开始:偏移(-1,0),结束:偏移(0,0)),
孩子:卡片(
颜色:颜色,红色,
孩子:ListTile(
标题:正文(
项目,,
样式:TextStyle(字体大小:20),
),
),
),
),
),
],
);
}
void _onButtonPress(){
_insertSingleItem();
}
void _insertSingleItem(){
String item=“Pig”;
int insertIndex=2;
_数据。插入(插入索引,项目);
_listKey.currentState.insertItem(insertIndex);
}
void _removeSingleItems(){
int-removeIndex=2;
字符串removedItem=\u data.removeAt(removeIndex);
//此生成器只是为了使动画具有某些特性
//在自
//原件已被删除。
AnimatedListRemovedItemBuilder=(上下文,动画){
//构建卡片小部件的方法。
返回_buildItem(removedItem,动画,方向:1);
};
_listKey.currentState.removeItem(removeIndex,生成器);
}
void _updateSingleItem(){
最终newValue=‘我喜欢羊’;
最终指数=3;
设置状态(){
_数据[索引]=新值;
});
}
}
在这里输入代码
您需要使用应用程序的发布版本测试性能。我将两个动画放在一个堆栈中,并包装了SlideTransition()在高度因子为零的align小部件中,它不会影响堆栈高度,并允许大小动画设置长方体高度的动画。您还可以将SizeTransition()包裹在不透明度()中,使其完全消失
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(title: Text('Update AnimatedList data')),
body: BodyWidget(),
),
);
}
}
class BodyWidget extends StatefulWidget {
@override
BodyWidgetState createState() {
return new BodyWidgetState();
}
}
class BodyWidgetState extends State<BodyWidget>
with SingleTickerProviderStateMixin {
// the GlobalKey is needed to animate the list
final GlobalKey<AnimatedListState> _listKey = GlobalKey(); // backing data
List<String> _data = ['Horse', 'Cow', 'Camel', 'Sheep', 'Goat'];
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
SizedBox(
height: 400,
child: AnimatedList(
key: _listKey,
initialItemCount: _data.length,
itemBuilder: (context, index, animation) {
return _buildItem(
_data[index],
animation,
);
},
),
),
RaisedButton(
child: Text(
'Insert single item',
style: TextStyle(fontSize: 20),
),
onPressed: () {
_onButtonPress();
},
),
RaisedButton(
child: Text(
'Remove single item',
style: TextStyle(fontSize: 20),
),
onPressed: () {
_removeSingleItems();
},
),
],
);
}
Widget _buildItem(String item, Animation<double> animation, {direction: 0}) {
return (direction == 0)
? SizeTransition(
sizeFactor: animation,
child: Card(
color: Colors.amber,
child: ListTile(
title: Text(
item,
style: TextStyle(fontSize: 20),
),
),
),
)
: Stack(
children: [
SizeTransition(
sizeFactor: animation,
child: Card(
color: Colors.transparent,
child: ListTile(
title: Text(
item,
style: TextStyle(fontSize: 20),
),
),
),
),
Align(
alignment: Alignment.topCenter,
heightFactor: 0,
child: SlideTransition(
position: animation
.drive(Tween(begin: Offset(-1, 0), end: Offset(0, 0))),
child: Card(
color: Colors.red,
child: ListTile(
title: Text(
item,
style: TextStyle(fontSize: 20),
),
),
),
),
),
],
);
}
void _onButtonPress() {
_insertSingleItem();
}
void _insertSingleItem() {
String item = "Pig";
int insertIndex = 2;
_data.insert(insertIndex, item);
_listKey.currentState.insertItem(insertIndex);
}
void _removeSingleItems() {
int removeIndex = 2;
String removedItem = _data.removeAt(removeIndex);
// This builder is just so that the animation has something
// to work with before it disappears from view since the
// original has already been deleted.
AnimatedListRemovedItemBuilder builder = (context, animation) {
// A method to build the Card widget.
return _buildItem(removedItem, animation, direction: 1);
};
_listKey.currentState.removeItem(removeIndex, builder);
}
void _updateSingleItem() {
final newValue = 'I like sheep';
final index = 3;
setState(() {
_data[index] = newValue;
});
}
}
enter code here