Flutter simply implements browser H5 particle animation
We have all the cool particle animations that H5 has, and flutter wants to have.
1. Old rule: Picture first!
2. Analysis of general ideas
1. Consider drawing dots first
As the opportunity creates corresponding points on the screen, the points will move by themselves, and the x and y axes will move at random speeds
When a point hits an edge, the velocity changes direction
2. Draw lines
A point is connected to other points within a certain distance, and the farther the distance, the less transparent the color
There should be a maximum number of connections
3. Mouse movement
The point where the mouse drops is connected to the point at a certain distance around it
3. Concrete implementation classes
1. Mouse listening event: MouseRegion
2. Redraw the control: CustomPainter
3. Customize view-related attributes
LiziConfig({
Key key,
@required this.context,
this.vx = 4.// Point x velocity, positive is right, negative is left
this.vy = 4.// Penalty y speed
this.radius = 2./ / some radius
this.count = 100./ / point number
this.color = const Color.fromRGBO(121.162.185.1.0),/ / some color
this.stroke = const Color.fromRGBO(130.255.255.1.0),// Line color
this.dist = 100.// Point adsorption distance
this.eDist = 130.// Mouse adsorption distance
this.maxConn = 10.// Maximum number of point-to-point connections
}) : super(key: key);
Copy the code
4. Point related attributes
class Point{
double x;/ / the x coordinate
double y;/ / y coordinates
double vx;// X-axis moving speed
double vy;// Y-axis moving speed
int conNum;// Number of connections
Point(this.x, this.y, this.vx, this.vy,this.conNum);
}
Copy the code
4. Detailed code
1. Draw the different points first
///Coordinates of the initialization point
for (int i = 0; i < count; i++) {
Point point=new Point(
Random().nextDouble()*MediaQuery.of(contextO).size.width,
Random().nextDouble()*MediaQuery.of(contextO).size.height,
vx / 2 - Random().nextDouble() * vx,
vy / 2 - Random().nextDouble() * vy,0);
points.add(point);
}
@override
void paint(Canvas canvas, Size sizes) {
///Draw some
for (int i = 0; i < points.length; i++) { canvas.drawCircle(Offset(points[i].x, points[i].y), radius.toDouble(),_paintPoint); }}Copy the code
2. Moving point
///Timer to change point position
const oneSec = const Duration(milliseconds: 40); // The interval is 1 second
qrtimer = new Timer.periodic(oneSec, (timer) {
_drawPoint();
});
///Moving point
void _drawPoint() {
setState(() {
if(points.isNotEmpty) {
for (int i = 0; i < count; i++) {
_borderPoint(points[i]);
points[i].conNum=0; }}}); }///Boundary processing
void _borderPoint(Point p) {
Size size=MediaQuery.of(context).size;
if(p.x<=0||p.x>=size.width){
p.vx=-p.vx;
p.x+=p.vx;
}else if(p.y<=0||p.y>=size.height){
p.vy = -p.vy;
p.y += p.vy;
}else{ p.x=p.x+p.vx; p.y=p.y+p.vy; }}Copy the code
3. Draw lines
for (int i = 0; i < points.length; i++) {
for (int j = 0; j < points.length; j++) {
if(i! =j){///If it's not the same point
///Figure out the distance between the two points
double dx=points[i].x-points[j].x;
double dy=points[i].y-points[j].y;
double distp=sqrt(dx*dx+dy*dy);
// print(" distp.tostring () ");
/// If the distance between two points is less than the adsorption distance and the maximum connection number, a line is drawn
if(distp <= dist && points[i].conNum <maxConn){
points[i].conNum++;
_paintLine.strokeWidth=0.5-distp/dist;
_paintLine.color=Color.fromRGBO(stroke.red, stroke.green, stroke.blue, 1-distp/dist);
canvas.drawLine(Offset(points[i].x, points[i].y), Offset(points[j].x, points[j].y), _paintLine);
}
///Mouse events
if(mouseY>0&&mouseX>0) {double dx=points[i].x-mouseX;
double dy=points[i].y-mouseY;
double distp=sqrt(dx*dx+dy*dy);
/// When the mouse adsorption distance is accelerated, directly change the x and Y values of the point to achieve the acceleration effect
if(distp > dist && distp <= eDist){
points[i].x = points[i].x + (mouseX - points[i].x) / 20;
points[i].y = points[i].y + (mouseY - points[i].y) / 20;
}
if(distp <= eDist){
_paintMouseLine.color=Color.fromRGBO(stroke.red, stroke.green, stroke.blue, 1-distp/eDist);
canvas.drawLine(Offset(points[i].x, points[i].y), Offset(mouseX, mouseY), _paintMouseLine);
}
}
}
}
}
Copy the code
4. Mouse events
@override
Widget build(BuildContext context) {
// TODO: implement build
return Container(
child: CustomPaint(
child: MouseRegion(
onEnter: (event){
/ / print (" enter the x: ${event. Position. Dx} y: ${event. Position. Dy} ");
_mouseEvent(event.position.dx,event.position.dy);
},
onExit: (event){
//print("onExit:${event.position.dx} y:${event.position.dy}");
_mouseEvent(- 1.- 1);
},
onHover: (event){
/ / print (" mobile x: ${event. Position. Dx} y: ${event. Position. Dy} ");
_mouseEvent(event.position.dx,event.position.dy);
},
),
painter: PaintLizi(
this.radius, this.count, this.color, this.stroke,this.maxConn,this.dist,points,this.mouseX,this.mouseY,this.eDist),
),
);
}
///Mouse events
void _mouseEvent(double x,double y){
setState(() {
mouseX=x;
mouseY=y;
Size size=MediaQuery.of(context).size;
if(mouseX>=size.width- 10||mouseX<=10){
mouseX=- 1;
}
if(mouseY>=size.height- 10||mouseY<=10){
mouseY=- 1; }}); }Copy the code
5. Problems encountered
Problem 1: MouseRegion wraps CustomPaint. The listening event is invalid as follows
///Listen event failure
return MouseRegion(
onEnter: (event){
},
child: CustomPaint(
painter: PaintLizi(
this.radius, this.count, this.color, this.stroke,this.maxConn,this.dist,points,this.mouseX,this.mouseY,this.eDist),
)
);
///The correct method MouseRegion is the child of CustomPaint
CustomPaint(
child: MouseRegion(
onEnter: (event){
/ / print (" enter the x: ${event. Position. Dx} y: ${event. Position. Dy} ");
_mouseEvent(event.position.dx,event.position.dy);
},
onExit: (event){
//print("onExit:${event.position.dx} y:${event.position.dy}");
_mouseEvent(- 1.- 1);
},
onHover: (event){
/ / print (" mobile x: ${event. Position. Dx} y: ${event. Position. Dy} ");
_mouseEvent(event.position.dx,event.position.dy);
},
),
painter: PaintLizi(
this.radius, this.count, this.color, this.stroke,this.maxConn,this.dist,points,this.mouseX,this.mouseY,this.eDist),
),
Copy the code
Problem 2: onExit: (event){}
The mouse remove event is not called back when the mouse moves out of the browser.