# flutter实现网易云音乐宇宙尘埃效果

## 1.老规矩，先上图

windows和和web端同样的效果。

## 2.思路分析

1.中间头像，不用说了，直接上旋转动画 RotationTransition

2.CustomPaint.

3.移动，

## 3.具体实现

### 1.定义对象

``````class Particle{
double x; //x轴坐标
double y;//y轴坐标
double opac;//透明度
double angle;//角度
}

### 2.定义view属性

``````String imgUrl;//头像地址
BuildContext context;
int count;///生成点个数
PartCircleView({Key key,
@required this.context,
this.imgUrl,
this.count=180})
: super(key: key);

### 3.画点

``````double w = MediaQuery.of(context).size.width / 2;
double h = MediaQuery.of(context).size.height / 2;

``````int distO=70;
double w = MediaQuery.of(context).size.width / 2;
double h = MediaQuery.of(context).size.height / 2;
for (int j = 0; j <= distO; j += 10) { ///产生越来越大的圆
for (int i = 0; i <= this.count; i++) {///产生固定数量的圆上的点
double angle =Random().nextDouble()*360;
if (angle <= 90) {
double x = w + (radius / 2 + j + 10) * sin(angle / 180 * pi);
double y = h - (radius / 2 + j + 10) * cos(angle / 180 * pi);
} else if (angle <= 180) {
double x = w + (radius / 2 + j + 10) * sin((angle - 90) / 180 * pi);
double y = h + (radius / 2 + j + 10) * cos((angle - 90) / 180 * pi);
} else if (angle <= 270) {
double x = w - (radius / 2 + j + 10) * sin((angle - 180) / 180 * pi);
double y = h + (radius / 2 + j + 10) * cos((angle - 180) / 180 * pi);
} else {
double x = w - (radius / 2 + j + 10) * sin((angle - 270) / 180 * pi);
double y = h - (radius / 2 + j + 10) * cos((angle - 270) / 180 * pi);
}
}
}

///画圆
@override
void paint(Canvas canvas, Size size) {
for (int i = 0; i < points.length; i++) {
_paintPoint.color = Color.fromRGBO(255, 255, 255, points[i].opac);
canvas.drawCircle(Offset(points[i].x, points[i].y), 1, _paintPoint);
}
}

### 4.移动点

``````const oneSec = const Duration(milliseconds: 220);
qrtimer = new Timer.periodic(oneSec, (timer) {
_drawPoint();
});

``````void _drawPoint() {
setState(() {
double w = MediaQuery.of(context).size.width / 2;
double h = MediaQuery.of(context).size.height / 2;
for (int i = 0; i < points.length; i++) {
///移动点
double angleTemp=points[i].angle+Random().nextDouble()*20-10; ///随机改变角度
if (angleTemp <= 90) {
} else if (angleTemp <= 180) {
points[i].x = w + addRadius * sin((angleTemp - 90) / 180 * pi);
points[i].y = h + addRadius * cos((angleTemp - 90) / 180 * pi);
} else if (angleTemp <= 270) {
points[i].x = w - addRadius * sin((angleTemp - 180) / 180 * pi);
points[i].y = h + addRadius * cos((angleTemp - 180) / 180 * pi);
} else {
points[i].x = w - addRadius * sin((angleTemp - 270) / 180 * pi);
points[i].y = h - addRadius * cos((angleTemp - 270) / 180 * pi);
}

///根据距离远近改变透明度
double dist = sqrt((points[i].x - w) * (points[i].x - w) +
(points[i].y - h) * (points[i].y - h));
points[i].opac = 1 - dist / (radius / 2 + distO + 10);

///当距离中心点大于最大距离或小于最小距离，回到最初的位置
if (dist >= (radius / 2 + distO + 10) || dist < (radius / 2 + 10)) {
double angle = points[i].angle;
if (angle <= 90) {
points[i].x = w + (radius / 2 + 10) * sin(angle / 180 * pi);
points[i].y = h - (radius / 2 + 10) * cos(angle / 180 * pi);
} else if (angle <= 180) {
points[i].x = w + (radius / 2 + 10) * sin((angle - 90) / 180 * pi);
points[i].y = h + (radius / 2 + 10) * cos((angle - 90) / 180 * pi);
} else if (angle <= 270) {
points[i].x = w - (radius / 2 + 10) * sin((angle - 180) / 180 * pi);
points[i].y = h + (radius / 2 + 10) * cos((angle - 180) / 180 * pi);
} else {
points[i].x = w - (radius / 2 + 10) * sin((angle - 270) / 180 * pi);
points[i].y = h - (radius / 2 + 10) * cos((angle - 270) / 180 * pi);
}
points[i].opac = 0;
}
}
});
}

## 4.其他控件代码

``````///旋转动画控制器
animationController = new AnimationController(
vsync: this,
duration: new Duration(milliseconds: 2500),
);
rotationAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation(parent: animationController, curve: Curves.linear));
animationController.repeat();

@override
Widget build(BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Stack(
children: [
Center(
),
Center(
child: new RotationTransition(
child: ClipOval(
child: Image(
image: NetworkImage(imgUrl),
fit: BoxFit.cover,
)),
turns: rotationAnimation,
),
),
Center(
child:Container(
) ,
),
Container(
child: CustomPaint(
),
)
],
),
);
}

///应用view
Container(
alignment: Alignment.center,
child: PartCircleView(context:context,
imgUrl:"https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=398732417,1147058696&fm=26&gp=0.jpg",