Reputation: 2448
I want to animate three balls falling on the screen. But i want the animation of the first ball to start sooner than the animation of the second ball and the animation of the second ball start a little sooner than the animation of the third ball.
I tried to give some sort of timeout in between the forward of the animatons but for some reason that didn't worked out. On the code bellow i acomplished the same animation for the three balls.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> with TickerProviderStateMixin {
AnimationController animationController1,
animationController2,
animationController3;
Animation<double> animation, animation2, animation3;
@override
void initState() {
animationController1 =
AnimationController(duration: Duration(milliseconds: 300), vsync: this);
animationController2 =
AnimationController(duration: Duration(milliseconds: 300), vsync: this);
animationController3 =
AnimationController(duration: Duration(milliseconds: 300), vsync: this);
animation = Tween(
begin: 0.0,
end: 1.0,
).animate(
CurvedAnimation(parent: animationController1, curve: Interval(0.0, 1.0)),
);
animation2 = Tween(
begin: 0.0,
end: 1.0,
).animate(
CurvedAnimation(parent: animationController2, curve: Interval(1.0, 2.0)),
);
animation3 = Tween(
begin: 0.0,
end: 1.0,
).animate(
CurvedAnimation(parent: animationController3, curve: Interval(2.0, 3.0)),
);
animationController1.addListener(() {
print('1 ${animation.value}');
print('2 ${animation.value}');
print('3 ${animation.value}');
setState(() {});
});
animationController1.addStatusListener((status) {
if (status == AnimationStatus.completed) {
animationController1.reverse();
} else if (status == AnimationStatus.dismissed) {
animationController1.forward();
}
});
animationController2.addStatusListener((status) {
if (status == AnimationStatus.completed) {
animationController2.reverse();
} else if (status == AnimationStatus.dismissed) {
animationController2.forward();
}
});
animationController3.addStatusListener((status) {
if (status == AnimationStatus.completed) {
animationController3.reverse();
} else if (status == AnimationStatus.dismissed) {
animationController3.forward();
}
});
animationController1.forward();
animationController2.forward();
animationController3.forward();
super.initState();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Container(
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
buildBallOne(),
SizedBox(
width: 6.0,
),
buildBallTwo(),
SizedBox(
width: 6.0,
),
buildBallThree()
],
),
),
),
),
);
}
Widget buildBallOne() {
return Container(
margin: EdgeInsets.only(top: 100 - (animationController1.value * 50)),
width: 35,
height: 35,
decoration: ShapeDecoration(
shape: CircleBorder(),
color: Colors.blue,
),
);
}
Widget buildBallTwo() {
return Container(
margin: EdgeInsets.only(top: 100 - (animationController2.value * 50)),
width: 35,
height: 35,
decoration: ShapeDecoration(
shape: CircleBorder(),
color: Colors.blue,
),
);
}
Widget buildBallThree() {
return Container(
margin: EdgeInsets.only(top: 100 - (animationController3.value * 50)),
width: 35,
height: 35,
decoration: ShapeDecoration(
shape: CircleBorder(),
color: Colors.blue,
),
);
}
}
Upvotes: 1
Views: 1232
Reputation: 16185
That's because you run all your controllers at the same time.
I've only added delays and made some tunes.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> with TickerProviderStateMixin {
AnimationController animationController1, animationController2, animationController3;
Animation<double> animation1, animation2, animation3;
@override
void initState() {
animationController1 = AnimationController(
duration: Duration(milliseconds: 600),
vsync: this,
);
animationController2 = AnimationController(
duration: Duration(milliseconds: 600),
vsync: this,
);
animationController3 = AnimationController(
duration: Duration(milliseconds: 600),
vsync: this,
);
animation1 = Tween(
begin: 0.0,
end: 1.0,
).animate(
CurvedAnimation(parent: animationController1, curve: Interval(0.0, 1.0)),
);
animation2 = Tween(
begin: 0.0,
end: 1.0,
).animate(
CurvedAnimation(parent: animationController2, curve: Interval(0.0, 1.0)),
);
animation3 = Tween(
begin: 0.0,
end: 1.0,
).animate(
CurvedAnimation(parent: animationController3, curve: Interval(0.0, 1.0)),
);
animationController1.addListener(() {
print('1 ${animation1?.value}');
print('2 ${animation2?.value}');
print('3 ${animation3?.value}');
setState(() {});
});
animationController1.addStatusListener((status) {
if (status == AnimationStatus.completed) {
animationController1.reverse();
} else if (status == AnimationStatus.dismissed) {
animationController1.forward();
}
});
animationController2.addStatusListener((status) {
if (status == AnimationStatus.completed) {
animationController2.reverse();
} else if (status == AnimationStatus.dismissed) {
animationController2.forward();
}
});
animationController3.addStatusListener((status) {
if (status == AnimationStatus.completed) {
animationController3.reverse();
} else if (status == AnimationStatus.dismissed) {
animationController3.forward();
}
});
Future.delayed(
Duration(milliseconds: 300),
() => animationController1.forward(),
);
Future.delayed(
Duration(milliseconds: 600),
() => animationController2.forward(),
);
Future.delayed(
Duration(milliseconds: 900),
() => animationController3.forward(),
);
super.initState();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Container(
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
buildBallOne(),
SizedBox(
width: 6.0,
),
buildBallTwo(),
SizedBox(
width: 6.0,
),
buildBallThree()
],
),
),
),
),
);
}
Widget buildBallOne() {
return Container(
margin: EdgeInsets.only(top: 100 - (animationController1.value * 50)),
width: 35,
height: 35,
decoration: ShapeDecoration(
shape: CircleBorder(),
color: Colors.blue,
),
);
}
Widget buildBallTwo() {
return Container(
margin: EdgeInsets.only(top: 100 - (animationController2.value * 50)),
width: 35,
height: 35,
decoration: ShapeDecoration(
shape: CircleBorder(),
color: Colors.blue,
),
);
}
Widget buildBallThree() {
return Container(
margin: EdgeInsets.only(top: 100 - (animationController3.value * 50)),
width: 35,
height: 35,
decoration: ShapeDecoration(
shape: CircleBorder(),
color: Colors.blue,
),
);
}
}
Actually because your animation path is the same for all balls, you could use one controller and calculate the position differently for each ball
P.s. use Animated Widget or AnimatedBuilder, to not trigger setState to refresh the page, it will provide better performance.
Upvotes: 1