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