【发布时间】:2021-07-30 11:58:06
【问题描述】:
我正在尝试创建动画屏幕,例如,当屏幕加载时,每个屏幕都将包含一个带有小部件的列。我想做的是,当屏幕加载时,让列中的每个小部件按照它们出现的顺序从屏幕外(从底部)浮动。
我一直在寻找,但似乎找不到解决方案。我怎样才能做到这一点?
【问题讨论】:
-
请添加您的代码。
我正在尝试创建动画屏幕,例如,当屏幕加载时,每个屏幕都将包含一个带有小部件的列。我想做的是,当屏幕加载时,让列中的每个小部件按照它们出现的顺序从屏幕外(从底部)浮动。
我一直在寻找,但似乎找不到解决方案。我怎样才能做到这一点?
【问题讨论】:
我做了一些可能是你想要的。但是,为了使每个元素在最后一个元素之后为自己而不是全部动画,我必须使用ListView.builder 来获取index。如果您能找到元素的index,则可以使用Column 小部件。
代码如下:
主屏幕:
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,
),
Container(
height: 32.0,
color: Colors.purple,
),
Container(
height: 32.0,
color: Colors.green,
),
Container(
height: 32.0,
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() 属性,没有它动画会搞砸。
【讨论】:
AutomaticKeepAliveClientMixin 添加到 FadeInFromBottom 小部件。我在FadeInFromBottom 小部件的状态中添加了 3 行代码。第一个是为FadeInFromBottom 的状态类声明的地方。第二个在类内部(添加getter wantKeepAlive),第三个在build 方法中(调用super.build(context))。请检查一下,让我知道它是否适合您。