android 飘雪浮动效果,Android自定义View实现飘雪效果

此博客给出了在Android中实现飘雪浮动效果的代码。定义了SnowView类,包含雪花的生成、绘制和运动逻辑。通过随机设置雪花的大小、颜色、速度等属性,利用贝塞尔曲线实现雪花飘落的曲线路径,还实现了雪花的旋转和循环绘制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

public class SnowView extends View {

private Paint snowPaint;

private Random random = new Random();

private List snows = new ArrayList<>();

private Handler handler = new Handler();

public SnowView(Context context, @Nullable AttributeSet attrs) {

super(context, attrs);

snowPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

snowPaint.setColor(Color.WHITE);

snowPaint.setStyle(Paint.Style.STROKE);

}

@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

super.onSizeChanged(w, h, oldw, oldh);

snows.clear();

for (int i = 0; i < 100; i++) {

snows.add(genASnow());

}

}

/**

* 生成一朵雪花

*

* @return

*/

private Snow genASnow() {

Snow snow = new Snow();

snow.setDegree(random.nextInt(60));

int radius = 10 + random.nextInt(10);//随机半径(雪花的大小)

snow.setRadius(radius);

snow.setWidth((int) (radius * 0.2));//雪花的粗细根据半径来计算

snow.setSpeed((int) (2 + Math.abs((radius - 20)) * 0.5));//雪花的速度:基础速度+随机值(根据雪花大小决定)

int red = random.nextInt(255);//随机一个颜色

int green = random.nextInt(255);

int blue = random.nextInt(255);

snow.setColor(Color.rgb(red, green, blue));

Point startPoint = new Point(random.nextInt(getWidth()), -random.nextInt(getHeight()));//雪花的起始点,也是第1个贝塞尔控制点

snow.setPointStart(startPoint);

snow.setPointControl(new Point(random.nextInt(getWidth()), random.nextInt(getHeight())));//雪花的起始点,也是第2个贝塞尔控制点

snow.setPointEnd(new Point(random.nextInt(getWidth()), getHeight() + random.nextInt(getHeight())));//雪花的起始点,也是第3个贝塞尔控制点

snow.setX(startPoint.x);

snow.setY(startPoint.y);

return snow;

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

canvas.drawColor(Color.BLACK);

//先绘制

for (int i = 0; i < snows.size(); i++) {

Snow snow = snows.get(i);

drawASnow(canvas, snow);

}

//进行Y轴的变换和角度的变换

for (int i = 0; i < snows.size(); i++) {

Snow snow = snows.get(i);

int y = snow.getY();

int d = snow.getDegree();

d = d + 1;

y += snow.getSpeed();

if (y >= snow.getPointEnd().y) {//当Y值在屏幕下方的时候重置到上方

y = -random.nextInt(getHeight());

}

snow.setY(y);

snow.setDegree(d);

}

handler.postDelayed(new Runnable() {

@Override

public void run() {

invalidate();

}

}, 10);

}

private void drawASnow(Canvas canvas, Snow snow) {

int snowX = snow.getX();

int snowY = snow.getY();

int snowRadius = snow.getRadius();

canvas.save();

snowPaint.setColor(snow.getColor());

snowPaint.setStrokeWidth(snow.getWidth());

canvas.rotate(snow.getDegree(), snowX, snowY);

for (int i = 0; i < 6; i++) {

//通过旋转的方式绘制雪花的6条边

int lineStartX = snowX;

int lineEndX = snowX + snowRadius;

int lineStartY = snowY;

int lineEndY = snowY;

//开始绘制雪花的分杈,分杈有两个与边的角度是60度,上边一个下边一个,分叉点的比例设置为0.6,分叉的长度设置为雪花半径的0.4

int line1StartX = (int) (lineStartX + snowRadius * 0.6);

double degree60R = Math.toRadians(60);

int line1EndX = (int) (line1StartX + Math.cos(degree60R) * snowRadius * 0.4);

int line1StartY = lineStartY;

int line1EndY = (int) (line1StartY - Math.sin(degree60R) * snowRadius * 0.4);

int line2StartX = (int) (lineStartX + snowRadius * 0.6);

int line2EndX = (int) (line1StartX + Math.cos(degree60R) * snowRadius * 0.4);

int line2StartY = lineStartY;

int line2EndY = (int) (line1StartY + Math.sin(degree60R) * snowRadius * 0.4);

//其实一朵雪花就是简单的直线绘制起来的

canvas.rotate(60, snowX, snowY);

canvas.drawLine(lineStartX, lineStartY, lineEndX, lineEndY, snowPaint);

canvas.drawLine(line1StartX, line1StartY, line1EndX, line1EndY, snowPaint);

canvas.drawLine(line2StartX, line2StartY, line2EndX, line2EndY, snowPaint);

}

canvas.restore();

}

private static class Snow {

private int width;

private int x;

private int y;

private int degree;

private int color;

private int radius;

private int speed;

//加入控制点的目的是为了实现贝塞尔路径的效果,因为雪花从天上飘下来肯定不会只直直的下来的,加上曲线路径会逼真一些

private Point pointStart;

private Point pointControl;

private Point pointEnd;

public Point getPointStart() {

return pointStart;

}

public void setPointStart(Point pointStart) {

this.pointStart = pointStart;

}

public Point getPointControl() {

return pointControl;

}

public void setPointControl(Point pointControl) {

this.pointControl = pointControl;

}

public Point getPointEnd() {

return pointEnd;

}

public void setPointEnd(Point pointEnd) {

this.pointEnd = pointEnd;

}

public int getSpeed() {

return speed;

}

public void setSpeed(int speed) {

this.speed = speed;

}

public int getRadius() {

return radius;

}

public void setRadius(int radius) {

this.radius = radius;

}

public int getWidth() {

return width;

}

public void setWidth(int width) {

this.width = width;

}

public int getX() {

float tick = y * 1.0f / (pointEnd.y - pointStart.y);

return BezierUtil.CalculateBezierPointForQuadratic(tick, pointStart, pointControl, pointEnd).x;

}

public void setX(int x) {

this.x = x;

}

public int getY() {

return y;

}

public void setY(int y) {

this.y = y;

}

public int getDegree() {

return degree;

}

public void setDegree(int degree) {

this.degree = degree;

}

public int getColor() {

return color;

}

public void setColor(int color) {

this.color = color;

}

}

public static class BezierUtil {

/**

* B(t) = (1 - t)^2 * P0 + 2t * (1 - t) * P1 + t^2 * P2, t ∈ [0,1]

*

* @param t 曲线长度比例

* @param p0 起始点

* @param p1 控制点

* @param p2 终止点

* @return t对应的点

*/

public static Point CalculateBezierPointForQuadratic(float t, Point p0, Point p1, Point p2) {

Point point = new Point();

float temp = 1 - t;

point.x = (int) (temp * temp * p0.x + 2 * t * temp * p1.x + t * t * p2.x);

point.y = (int) (temp * temp * p0.y + 2 * t * temp * p1.y + t * t * p2.y);

return point;

}

/**

* B(t) = P0 * (1-t)^3 + 3 * P1 * t * (1-t)^2 + 3 * P2 * t^2 * (1-t) + P3 * t^3, t ∈ [0,1]

*

* @param t 曲线长度比例

* @param p0 起始点

* @param p1 控制点1

* @param p2 控制点2

* @param p3 终止点

* @return t对应的点

*/

public static Point CalculateBezierPointForCubic(float t, Point p0, Point p1, Point p2, Point p3) {

Point point = new Point();

float temp = 1 - t;

point.x = (int) (p0.x * temp * temp * temp + 3 * p1.x * t * temp * temp + 3 * p2.x * t * t * temp + p3.x * t * t * t);

point.y = (int) (p0.y * temp * temp * temp + 3 * p1.y * t * temp * temp + 3 * p2.y * t * t * temp + p3.y * t * t * t);

return point;

}

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值