问题描述
我正在尝试创建动画屏幕,例如,当屏幕加载时,每个屏幕都会包含一个带有小部件的列。我想要做的是,当加载屏幕时,让列中的每个小部件按照它们出现的顺序从屏幕外(从底部)浮动。
我一直在寻找,但似乎找不到解决方案。我怎样才能做到这一点?
解决方法
我已经做了一些可能是你想要的。但是,为了使每个元素在最后一个元素之后为自己设置动画,而不是全部在一起,我必须使用 ListView.builder
来获取 index
。如果您能找出元素的 Column
,则可以使用 index
小部件。
代码如下:
主屏幕:
import 'package:flutter/material.dart';
import 'package:testing/fade_in_from_bottom.dart';
void main() => runApp(App());
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',debugShowCheckedModeBanner: false,theme: ThemeData(
primarySwatch: Colors.blue,),home: HomePage(),);
}
}
class HomePage extends StatelessWidget {
final List<Widget> children = <Widget>[
Container(
height: 32.0,color: Colors.amber,Container(
height: 32.0,color: Colors.black,color: Colors.purple,color: Colors.green,color: Colors.indigo,];
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: children.length,itemBuilder: (BuildContext context,int index) {
return FadeInFromBottom(
key: UniqueKey(),// this is very important
index: index,child: children[index],);
},],);
}
}
这是我制作的 FadeInFromBottom
小部件:
import 'package:flutter/material.dart';
class FadeInFromBottom extends StatefulWidget {
@override
_FadeInFromBottomState createState() => _FadeInFromBottomState();
final Key key;
final Duration animationDuration;
final Duration offsetDuration;
final Widget child;
final int index;
FadeInFromBottom({
@required this.key,@required this.child,@required this.index,this.animationDuration = const Duration(milliseconds: 400),this.offsetDuration = const Duration(milliseconds: 800),}) : super(key: key); // this line is important
}
// How to add AutomaticKeepAliveClientMixin? Follow steps 1,2 and 3:
// 1. add AutomaticKeepAliveClientMixin to FadeInFromBottom widget State
class _FadeInFromBottomState extends State<FadeInFromBottom>
with TickerProviderStateMixin,AutomaticKeepAliveClientMixin {
bool get wantKeepAlive => true; // 2. add this line
double progress = 0.0;
Animation<double> animation;
AnimationController controller;
@override
void initState() {
super.initState();
final Duration offsetDuration =
widget.offsetDuration == null ? 0.0 : widget.offsetDuration;
final int index = widget.index == null ? 0 : widget.index;
// we await the future to create the animation delay
Future.delayed(offsetDuration * index).then(
(_) {
controller = AnimationController(
duration: widget.animationDuration,vsync: this);
animation = Tween<double>(begin: 0.0,end: 1.0).animate(
CurvedAnimation(
parent: controller,curve: Curves.linear,)..addListener(() {
setState(() => progress = animation.value);
});
controller.forward();
},);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
super.build(context); // 3. add this line
return Opacity(
opacity: progress,child: Transform.translate(
offset: Offset(
0.0,(1.0 - progress) * 999.0,child: widget.child,);
}
}
不要忘记添加 key: UniqueKey()
属性,如果没有它,动画会变得一团糟。