I want to add some animations to some widgets in my app, but these widget are not visible until the user scroll down.
I'd like for these animations to happen when the widget becomes visible, Generally I'd start the animation in initState
but this only make the animation when the widget is first drawn, not when it becomes visible to the user .
Is there any such event to listen to ? If not I imagine I can play with Viewport or aspect ratio or MediaQuery?
GlobalKey
and an AnimationController
for each of your widgets.ScrollController
to listen for scroll events in your scroll view (doesn't have to be a ListView
)GlobalKey.currentContext.findRenderObject()
to get the reference to the actual object that is rendered on screen.RenderObject
exists, get its relative position (getTransformTo
) and check if the position is visible in the scroll viewAnimationStatus
of the 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'),
)
],
),
);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With