Android 轮子之下雪动画效果
先来看看今天的效果吧:
还是咋们的老套路,先来分析一波:
- 效果图中的雪花其实是一些白色的圆
- 随机大小的圆
- 一直向下移动,其实是y轴向下
- 有左右飘动的效果,其实是x轴左右飘动
自定义圆
public class SnowFlakeView extends View {
private int height;//屏幕高
private int width;//屏幕宽
public SnowFlakeView(Context context) {
this(context, null);
}
public SnowFlakeView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
//定义画笔
Paint paint = new Paint();
public SnowFlakeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
paint.setColor(Color.WHITE);//设置画笔颜色
paint.setAntiAlias(true);//设置画笔去锯齿
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//画圆
canvas.drawCircle(100,100,50,paint);
}
@Override//计算布局大小
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthmeasure = measure(widthMeasureSpec);
int heightmeasure = measure(heightMeasureSpec);
setMeasuredDimension(widthmeasure,heightmeasure);
}
private int measure(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.UNSPECIFIED) {
result = 200;
} else {
result = specSize;
}
return result;
}
}
效果图(1.1)
:
这段代码很简单,就是绘制了一个dx == 100 dy == 100半径为50的白色圆,就不解释了
接下来使用Bean类写:
class SnowBean {
//坐标 用来记录x和y
Position position new Position(100,100) ;
//大小 用来记录半径大小
double size = 50;
public double getSize() {
return size;
}
public void setSize(double size) {
this.size = size;
}
public Position getPosition() {
return position;
}
public void setPosition(Position position) {
this.position = position;
}
//用来记录x 和 y
static class Position {
double x;
double y;
public Position(double x, double y) {
this.x = x;
this.y = y;
}
}
}
重新绘制View
public class SnowFlakeView extends View {
.....
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
SnowBean snowBean = new SnowBean();
canvas.drawCircle((float)snowBean.position.x,(float)snowBean.position.y, (float) snowBean.size,paint);
}
}
效果图(1.2)
:
可以看到效果图(1.2)
和效果图(1.1)
是一模一样的~
到这里就非常nice了,接下来创建圆
创建300个随机大小的白色圆并绘制
public class SnowFlakeView extends View {
private int height;//屏幕高
private int width;//屏幕宽
.....
public SnowFlakeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
paint.setColor(Color.WHITE);
paint.setAntiAlias(true);
//获取屏幕宽度
Resources resources = this.getResources();
DisplayMetrics dm = resources.getDisplayMetrics();
width = dm.widthPixels;
height = dm.heightPixels;
//初始化数据
initData();
}
//初始化雪花
private void initData() {
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 300; i++) {
SnowBean snowBean = new SnowBean();
//随机起始位置 mRandom.nextDouble()取值为0-1
snowBean.setPosition(new SnowBean.Position(mRandom.nextDouble() * width, mRandom.nextDouble() * height));
//随机偏移幅度 mRandom.nextDouble()取值为0-1
snowBean.setDeviation(mRandom.nextDouble() + 2);
//随机雪花大小 mRandom.nextDouble()取值为0-1 得到5-10之间的公式: mRandom.nextInt(MAX - MIN + 1) + MIN;
snowBean.setSize(mRandom.nextInt(10 - 5 + 1) + 5);
mList.add(snowBean);
}
}
}).start();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//循环绘制雪花!
for (int i = 0; i < mList.size(); i++) {
SnowBean snowBean = mList.get(i);
canvas.drawCircle((float) snowBean.position.x, (float) snowBean.position.y, (float) snowBean.size, paint);
}
}
}
效果图(1.3)
:
接下来让他动起来就可以完成今天的效果啦~
让他动起来肯定用来了动画,这里我们用到了属性动画,有对属性动画不熟悉的朋友可以查看Animation动画(二)PropertyAnimation属性动画
添加动画
public class SnowFlakeView extends View {
public SnowFlakeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
.....
//初始化数据
initData();
// //刷新数据
Refresh();
}
//使用属性动画
public void Refresh() {
//设置移动的位置
ValueAnimator valueAnimator = ValueAnimator.ofInt(0);
//通过addUpdateListener来监听ofInt的变化
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//刷新
initRefresh();
}
});
//设置动画模式无限滚动等
valueAnimator.setRepeatCount(INFINITE);
valueAnimator.setRepeatMode(RESTART);
valueAnimator.start();
}
//刷新
private void initRefresh() {
for (int i = 0; i < mList.size(); i++) {
SnowBean snowBean = mList.get(i);
//重新绘制雪花, 新雪花x = 旧的雪花x + 随机偏移度数
snowBean.position.x = snowBean.position.x + snowBean.deviation;
//新的雪花y = 旧的雪花y + 雪花下降速度speed + 随机运行速度
snowBean.position.y = snowBean.position.y + snowBean.getSpeed();
//重置高度 当雪花y出屏幕时 则让他归0重新绘制 height是屏幕高度
if (snowBean.position.y > height) {
snowBean.position.y = 0;
}
//重置宽度 当雪花x 出屏幕时,让他归0重新绘制 width是屏幕宽度
if (snowBean.position.x > width) {
snowBean.position.x = 0;
}
}
//刷新onDraw
invalidate();
}
}
咋们先来分析这个方法里面的代码:
//使用属性动画
public void Refresh() {
//设置移动的位置
ValueAnimator valueAnimator = ValueAnimator.ofInt(0);
//通过addUpdateListener来监听ofInt的变化
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//刷新
initRefresh();
}
});
//设置动画模式无限滚动等
valueAnimator.setRepeatCount(INFINITE);
valueAnimator.setRepeatMode(RESTART);
valueAnimator.start();
}
在这里,主要不是为了使用这个方法,主要是为了使用:
//设置动画模式无限滚动等
valueAnimator.setRepeatCount(INFINITE);
valueAnimator.setRepeatMode(RESTART);
valueAnimator.start();
这块代码让他无限的滚动,并且通过:
ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//刷新
initRefresh();
}
});
监听,一直不断地重复执行initRefresh();方法,让雪一直动起来~
在来看看initRefresh()方法:
//刷新
private void initRefresh() {
for (int i = 0; i < mList.size(); i++) {
SnowBean snowBean = mList.get(i);
//重新绘制雪花, 新雪花x = 旧的雪花x + 随机偏移度数
snowBean.position.x = snowBean.position.x + snowBean.deviation;
//新的雪花y = 旧的雪花y + 雪花下降速度speed + 随机运行速度
snowBean.position.y = snowBean.position.y + snowBean.getSpeed();
//重置高度 当雪花y出屏幕时 则让他归0重新绘制 height是屏幕高度
if (snowBean.position.y > height) {
snowBean.position.y = 0;
}
//重置宽度 当雪花x 出屏幕时,让他归0重新绘制 width是屏幕宽度
if (snowBean.position.x > width) {
snowBean.position.x = 0;
}
}
//刷新onDraw
invalidate();
}
分析:
比如当前的x = 10,y = 10; 那么在第一次刷新的时候
让x加上左右移动的随机数
让y加上随机的下降速度
若现在左右移动的随机数是0.5,下降速度是6,则x坐标变为10.5,y坐标变为16,重新绘制的时候当前的雪花(圆):
从x = 10 , y = 10 变化到x = 10.5 , y = 16
并且使用invalidate()重新绘制onDraw()让雪重新绘制,则达到了一直下雪的效果
//重置高度 当雪花y出屏幕时 则让他归0重新绘制 height是屏幕高度
if (snowBean.position.y > height) {
snowBean.position.y = 0;
}
//重置宽度 当雪花x 出屏幕时,让他归0重新绘制 width是屏幕宽度
if (snowBean.position.x > width) {
snowBean.position.x = 0;
}
若果雪花(圆)移动出屏幕时,则让他的x,和y回到起始位置(0),这样一直循环,雪(圆)也会一直下~
效果图(1.4)
:
注:
我的项目之中有和Flutter混合开发的东西,如果你没有Flutter下载LoveView即可,否则的话可能你跑不起来哦~
猜你喜欢:
原创不易,您的点赞就是对我最大的支持,留下您的点赞以及评论吧~