See Github /flutter_journey for all source code
1. What is animation
1.1: Animation description
See words such as face, will move the picture. Picture continuous rendering, when the speed to a certain extent, the brain will present dynamic
1). What is motion: Visually, an object appears in different physical positions on different timelines 2). Displacement = initial displacement + velocity * time Velocity = initial velocity + acceleration * time Time, displacement, velocity and acceleration constitute the motion system of modern scienceCopy the code
1.2: about FPS
How fast should the refresh be? I don’t know if you’ve ever heard of an FPS, but yes, an important FPS in that game
A refresh rate of 60Hz means that the screen is refreshed 60 times Per Second, which is 60 Frames Per Second. In the common case of movies, 24 FPS, which is 24 Frames Per Second. To achieve fluency, you need 60fps, which is a metric in the game, otherwise you will feel no fluency. 60 refreshes per second, which is 16.666667ms, is also a common valueCopy the code
1.3: Animation in code
You can use code to simulate motion, changing the properties of the moving object while constantly refreshing to create animation
ValueAnimator in Android, and ‘ ‘in JavaScript(browser).
1. Time: Run ---- indefinitely to simulate the time stream. Refresh the interval each time, denoted as: 1T 2. Displacement: The position of the object in the screen pixels ---- simulation world, each pixel distance is denoted as :1px 3. Speed (px/T), acceleration (px/T^2) Note: The ideas in this section apply to any language where time and displacement can be simulated, but the syntax is different, rightCopy the code
2. Particle animation
2.1. Time flow in Flutter
Implement a constantly refreshed stage with AnimationController, and the show is up to you
class RunBall extends StatefulWidget { @override _RunBallState createState() => _RunBallState(); } class _RunBallState extends State<RunBall> with SingleTickerProviderStateMixin { AnimationController controller; var _oldTime = DateTime.now().millisecondsSinceEpoch; @override Widget build(BuildContext context) {var child = Scaffold(); Return GestureDetector(// gesturing component, do click in response child: Child, onTap: () {controller.forward(); // Execute the animation},); } @override void initState() {controller =// Create AnimationController object AnimationController(duration: duration (days:)) 999 * 365), vsync: this); Controller.addlistener (() {// Add listeners and render(); }); } @override void dispose() { controller.dispose(); {setState(() {var now = datetime.now ().millisecondssinceepoch;} Print (" ${now-_oldtime}ms"); // Print the time difference _oldTime = now; // Reassign}); }}Copy the code
2.2: Drawing static ball
It’s time for our Canvas again
Class Ball {double aX; // Double aY; // Acceleration Y double vX; // speed X double vY; // speed Y double x; // double y; // select * from Y where Y = 1; // Double r; X=0, this.y=0, this.color, this.r=10, this.ax =0, this.ay =0, this.vx =0, this.vy =0}); } Painter class RunBallView extends CustomPainter {Ball _ball; // Rect_area; // Paint mPaint; // Paint the main brush. RunBallView(this._ball,this._area) {mPaint = new Paint(); bgPaint = new Paint().. color = Color.fromARGB(148, 198, 246, 248); } @override void paint(Canvas canvas, Size size) { canvas.drawRect(_area, bgPaint); _drawBall(canvas, _ball); } @override bool shouldRepaint(CustomPainter oldDelegate) { return true; } void _drawBall(canvas canvas, ball ball) {canvas.drawcircle (Offset(ball.x, ball.y), drawCircle(Offset(ball.x, ball.y)); ball.r, mPaint.. color = ball.color); }} var _area= rect.fromltrb (0+40.0,0+200.0,280+40.0,200+200.0); Var_ball = Ball(color: Colors. BlueAccent, r: 10,x: 40.0+140,y:200.0+100); ---->[use :_RunBallState#build]---- var child = Scaffold(body: CustomPaint(painter: RunBallView(_ball,_area),),);Copy the code
2.3: remote box
This means that the ball changes its properties each time it is refreshed, so that it is visually in motion
After the collision at the boundary, the direction can be changed, and through the following three steps, a motion box is completed
Var _ball = Ball(color: Colors. BlueAccent, R: 10,aY: 0.1, vX: 2, vY: -2,x: 40.0+140, Y: 200.0+100); //[1]. //[2]. {render() {updateBall(); setState(() { var now = DateTime.now().millisecondsSinceEpoch; Print (" lag: ${now - _oldTime} ms, frame rate: ${1000 / (now - _oldTime)} "); _oldTime = now; }); } //[3]. UpdateBall information void updateBall() {// kinematics formula _ball.x += _ball.vx; _ball.y += _ball.vY; _ball.vX += _ball.aX; _ball.vY += _ball.aY; Y > _area.bottom-_ball.r) {_ball.y = _area.bottom-_ball.r; _ball.vY = -_ball.vY; _ball.color=randomRGB(); Y < _area.top + _ball.r) {_ball.y = _area.top + _ball.r; _ball.vY = -_ball.vY; _ball.color=randomRGB(); If (_ball.x < _area.left + _ball.r) {_ball.x = _area.left + _ball.r; _ball.vX = -_ball.vX; _ball.color=randomRGB(); If (_ball.x > _area.right-_ball.r) {_ball.x = _area.right-_ball.r; _ball.vX= -_ball.vX; _ball.color=randomRGB(); // Random color after collision}}}Copy the code
2.4: Make the ball move according to the specified function image
Given a small dx, as dx increases, find the dy in terms of the function, and then update the ball
In the following sine image, with each update, the spherical coordinate values are constrained according to the functional relationship
Double dx = 0.0; void updateBall(){ dx+=pi/180; _ball.x+=dx; _ball.y+=f(dx); } f(x){ var y= 5*sin(4*x); // Return y; }Copy the code
Or you can make the ball move in a circle, and here’s how to make it move in a circle by using a parametric equation
It means to be good at math, to run as fast as you want.
Double dx = 0.0; void updateBall(){ dx+=pi/180; // Add PI / 180_ball. X +=cos(dx); _ball.y+=sin(dx); }Copy the code
3. The beam
3.1: Motion of multiple particles
One particle moving is fun enough, but what about many particles?
What needs to be changed is the RunBallView input, from a ball to a list of balls, drawn in batches when drawing, and updated in batches when updating information
[1]. Class RunBallView extends CustomPainter {List<Ball> _balls; Void paint(Canvas, Size Size) {_balls.forEach((ball) {_drawBall(Canvas, ball); }); } //[3]. _render() {for (var I = 0; i < _balls.length; i++) { updateBall(i); } setState(() { }); } //[4]._runballState for (var I = 0; i < 30; i++) { _balls.add(Ball( color: randomRGB(), r: 5 + 4 * random.nextDouble(), vX: 3* random.nextdouble ()*pow(-1, random.nextint (20)), aY: 0.1, x: 200, y: 300)); }Copy the code
You might think it’s okay to draw a little ball, but a little ball is just a cell,
You can replace it with anything you can draw, even pictures or components
3.2: Impact splitting effect
That is, particles can be added at the right time to achieve a certain visual effect
The core is to process when the boundary is reached by halving the radius of the original particle and adding another particle with equal inverse
If (ball.y > _area.bottom) {var newBall = ball.fromball (ball); newBall.r = newBall.r / 2; newBall.vX = -newBall.vX; newBall.vY = -newBall.vY; _balls.add(newBall); ball.r = ball.r / 2; ball.y = _area.bottom; ball.vY = -ball.vY; ball.color = randomRGB(); // Random color after collision}Copy the code
When dividing more and more, there will be a lot of drawing, then you can control the condition to remove
void updateBall(int i) { var ball = _balls[i]; If (ball.r < 0.3) {// remove _balls.removeat (I); } / / slightly... }Copy the code
3.3: Specific particles
Now you can feel that animation is the feeling that the information of the element is constantly changing
As long as the information is described well, then you can do any animation, you are the creator and the master
/ apply colours to a drawing number * * * * @ param num to display digital * @ param canvas canvas * / void renderDigit radius, (double) {var one = [[0, 0, 0, 1, 1, 0, 0], [0, 1, 1, 1, 1, 0, 0] to [0, 0, 0, 1, 1, 0, 0] to [0, 0, 0, 1, 1, 0, 0] to [0, 0, 0, 1, 1, 0, 0] to [0, 0, 0, 1, 1, 0, 0]. [0, 0, 0, 1, 1, 0, 0] to [0, 0, 0, 1, 1, 0, 0] to [0, 0, 0, 1, 1, 0, 0], [1, 1, 1, 1, 1, 1, 1]]. //1 for (int i = 0; i < one.length; i++) { for (int j = 0; j < one[j].length; j++) { if (one[i][j] == 1) { double rX = j * 2 * (radius + 1) + (radius + 1); Double rY = I * 2 * (radius + 1) + (radius + 1); Balls. add(Ball(r: radius, x: rX, y: rY, color: randomRGB(), vX: 3 * random.nextDouble() * pow(-1, random.nextInt(20)), vY: 3 * random.nextDouble() * pow(-1, random.nextInt(20)))); }}}}Copy the code
Using a two-dimensional array to record the information of the point position, the drawing can be judged at the time of rendering the intended effect
It then creates balls with information, renders them, and animates them. In fact, through the pixel point can also record these information, you can make the picture particle painting, before the Android particle article Bitmap pixel level operation written very information, here do not expand
In general, animation consists of three important conditional time streams, rendering rendering, and information update logic
This is not just for Flutter, any language that satisfies these three points, particle animation can run. What’s the use, maybe to remind me that I’m not a brick loader, but a programmer a Creater…
conclusion
As we come to the end of this article, if you want to have a quick taste of the new Flutter, Seven Days of Flutter is for you. If you want to explore it, follow my footsteps and take a Flutter tour. In addition, I have a Wechat communication group with Flutter. Welcome to join my wechat group to discuss the problem of Flutter. My wechat signal is ZDL1994328.
See Github /flutter_journey for all source code