问题
I'm currently using an AnimatedList in my Flutter app and having problems with the way removed list items are animated out.
The animation itself works as expected but once the removed item finishes animating, it just disappears causing the other widgets to jump into its place. I had expected the other items to transition into the place of the removed item ...
I tried wrapping my list items with a ScaleTransition
but that didn't help - the other list items still do not react to the removed item until it has finished the animation.
This kind of defies the purpose of AnimatedList, right? Or did I do something wrong? The "Widget of the week" video about AnimatedList clearly shows that list items react to newly inserted items by changing their position ...
Here is my code:
@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,
),
),
);
}
}
And then somewhere in the MyCustomWidget I invoke this function:
void _remove(BuildContext context) async {
final animatedList = AnimatedList.of(context);
// obtain myModel asynchronously
myModel.removeData(data);
animatedList.removeItem(index, (context, animation) => MyCustomWidget(
data: data,
animation: animation,
disabled: true,
), duration: Duration(milliseconds: 350));
}
回答1:
The key is to trigger two Transitions one SlideTranstion() and another SizeTransition to eliminate to jump when the item is removed
here is some sample code
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
来源:https://stackoverflow.com/questions/60576765/flutter-animatedlist-still-janky