flutter 简单实现浏览器H5粒子动画
我们常见H5炫酷的粒子动画,H5有的,flutter都想拥有。
1.老规矩先上图!
2.大致思路分析
1.先考虑画点
随机会在屏幕上产生相应的点,点会自己移动 ,x,y轴移动速度也是随机的
当点在碰到边缘时,速度变方向
2.画线
一个点和周围一定距离内的点相连,距离越远颜色透明度越低
应该要有最大连接数
3.鼠标移动
鼠标落下的点与周围一定距离的点相连
3.具体实现类
1.鼠标监听事件:MouseRegion
2.重绘控件 :CustomPainter
3.自定义view相关属性
LiziConfig({
Key key,
@required this.context,
this.vx = 4,//点x轴速度,正为右,负为左
this.vy = 4,//点球y轴速度
this.radius = 2,//点半径
this.count = 100,//点个数
this.color = const Color.fromRGBO(121, 162, 185, 1.0),//点颜色
this.stroke = const Color.fromRGBO(130, 255, 255, 1.0),//线条颜色
this.dist = 100,//点吸附距离
this.eDist = 130,//鼠标吸附距离
this.maxConn = 10,//点到点最大连接数
}) : super(key: key);
复制代码
4.点相关属性
class Point{
double x;//x轴坐标
double y;//y轴坐标
double vx;//x轴移动速度
double vy;//y轴移动速度
int conNum;//点连接数量
Point(this.x, this.y, this.vx, this.vy,this.conNum);
}
复制代码
4.详细代码
1.先画出不同的点
///初始化点的坐标
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) {
///画点
for (int i = 0; i < points.length; i++) {
canvas.drawCircle(Offset(points[i].x, points[i].y),
radius.toDouble(),_paintPoint);
}
}
复制代码
2.移动点
///定时器去更改点位置
const oneSec = const Duration(milliseconds: 40); //间隔1秒
qrtimer = new Timer.periodic(oneSec, (timer) {
_drawPoint();
});
///移动点
void _drawPoint() {
setState(() {
if(points.isNotEmpty) {
for (int i = 0; i < count; i++) {
_borderPoint(points[i]);
points[i].conNum=0;
}
}
});
}
///边界处理
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;
}
}
复制代码
3.画线
for (int i = 0; i < points.length; i++) {
for (int j = 0; j < points.length; j++) {
if(i!=j){///如果不是同一个点
///算出两点间的距离
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(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);
}
///鼠标事件
if(mouseY>0&&mouseX>0){
double dx=points[i].x-mouseX;
double dy=points[i].y-mouseY;
double distp=sqrt(dx*dx+dy*dy);
/// 遇到鼠标吸附距离时加速,直接改变point的x,y值达到加速效果
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);
}
}
}
}
}
复制代码
4.鼠标事件
@override
Widget build(BuildContext context) {
// TODO: implement build
return Container(
child: CustomPaint(
child: MouseRegion(
onEnter: (event){
//print("进入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("移动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),
),
);
}
///鼠标事件
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;
}
});
}
复制代码
5.遇到的问题
问题1:MouseRegion包裹CustomPaint,监听事件失效,如下
///监听事件失效
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),
)
);
///正确方法 MouseRegion作为CustomPaint的child
CustomPaint(
child: MouseRegion(
onEnter: (event){
//print("进入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("移动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),
),
复制代码
问题2:onExit: (event){}
鼠标移除事件在鼠标移到浏览器外并没有回调。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END