我想在我的应用程序的某些小部件中添加一些动画,但是这些小部件在用户向下滚动之前不可见。
我希望这些动画在小部件可见时发生,通常我会在initState
中启动动画,但这只会在第一次绘制小部件时才制作动画,而不是在对小部件可见时才制作动画用户。
有没有这样的事件要听?如果不是,我想我可以使用视口或宽高比或MediaQuery吗?
答案 0 :(得分:5)
GlobalKey
和一个AnimationController
。ScrollController
来监听滚动视图中的滚动事件(不必是ListView
)GlobalKey.currentContext.findRenderObject()
获取对在屏幕上呈现的实际对象的引用。RenderObject
存在,请获取其相对位置(getTransformTo
),并检查该位置在滚动视图中是否可见AnimationStatus
中的AnimationController
。
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Playground',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new TestPage(),
);
}
}
class TestPage extends StatefulWidget {
@override
_TestPageState createState() => new _TestPageState();
}
class _TestPageState extends State<TestPage> with SingleTickerProviderStateMixin {
final listViewKey = new GlobalKey();
final animatedBoxKey = new GlobalKey();
final scrollController = new ScrollController();
AnimationController animatedBoxEnterAnimationController;
@override
void initState() {
super.initState();
animatedBoxEnterAnimationController = new AnimationController(
vsync: this,
duration: Duration(milliseconds: 2000),
);
scrollController.addListener(() {
_updateAnimatedBoxEnterAnimation();
});
}
static const enterAnimationMinHeight = 100.0;
_updateAnimatedBoxEnterAnimation() {
if (animatedBoxEnterAnimationController.status != AnimationStatus.dismissed) {
return; // animation already in progress/finished
}
RenderObject listViewObject = listViewKey.currentContext?.findRenderObject();
RenderObject animatedBoxObject = animatedBoxKey.currentContext?.findRenderObject();
if (listViewObject == null || animatedBoxObject == null) return;
final listViewHeight = listViewObject.paintBounds.height;
final animatedObjectTop = animatedBoxObject.getTransformTo(listViewObject).getTranslation().y;
final animatedBoxVisible = (animatedObjectTop + enterAnimationMinHeight < listViewHeight);
if (animatedBoxVisible) {
// start animation
animatedBoxEnterAnimationController.forward();
}
}
@override
Widget build(BuildContext context) {
final boxOpacity = CurveTween(curve: Curves.easeOut).animate(animatedBoxEnterAnimationController);
final boxPosition = Tween(begin: Offset(-1.0, 0.0), end: Offset.zero)
.chain(CurveTween(curve: Curves.elasticOut))
.animate(animatedBoxEnterAnimationController);
return new Scaffold(
appBar: new AppBar(
title: new Text('Flutter Playground'),
),
body: new ListView(
key: listViewKey,
controller: scrollController,
children: <Widget>[
new Container(
padding: EdgeInsets.all(16.0),
child: new Text(
'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.',
style: TextStyle(fontSize: 24.0),
),
),
new FadeTransition(
opacity: boxOpacity,
child: new SlideTransition(
position: boxPosition,
child: new Container(
key: animatedBoxKey,
height: 300.0,
color: Colors.green,
padding: EdgeInsets.all(16.0),
child: new Text('Animated Box'),
),
),
),
new Container(
padding: EdgeInsets.all(16.0),
child: new Text(
'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.',
style: TextStyle(fontSize: 24.0),
),
),
new FlatButton(
onPressed: () {
scrollController.jumpTo(0.0);
animatedBoxEnterAnimationController.reset();
},
child: new Text('Reset'),
)
],
),
);
}
}