畫面持續生成小愛心圖片,從頂部隨機 X 位置飄落,過程中伴隨左右搖擺、旋轉、縮放、透明度漸變,落地或超出屏幕後回收複用。
public class FallingHeartsView extends View {
private final List hearts = new ArrayList<>();
private final Random rnd = new Random();
private final ValueAnimator animator = ValueAnimator.ofFloat(0, 1).setDuration(16); // 60fps
public FallingHeartsView(Context ctx) { super(ctx); init(); }
private void init() {
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.addUpdateListener(a -> {
updateHearts();
invalidate();
});
animator.start();
}
private void updateHearts() {
// 1. 概率生成新愛心
if (rnd.nextFloat() < 0.05f) hearts.add(new Heart(getWidth()));
// 2. 更新現有愛心
Iterator it = hearts.iterator();
while (it.hasNext()) {
Heart h = it.next();
h.y += h.speedY;
h.x += Math.sin(h.angle) * h.swing; // 左右搖擺
h.angle += 0.05f;
h.scale -= 0.001f; // 逐漸縮小
h.alpha -= 5; // 逐漸透明
if (h.y > getHeight() || h.alpha <= 0) it.remove();
}
}
@Override
protected void onDraw(Canvas canvas) {
for (Heart h : hearts) {
if (h.alpha > 0) {
canvas.save();
canvas.translate(h.x, h.y);
canvas.rotate(h.angle * 180 / (float)Math.PI);
canvas.scale(h.scale, h.scale);
paint.setAlpha(h.alpha);
canvas.drawBitmap(heartBitmap, -heartBitmap.getWidth()/2f, -heartBitmap.getHeight()/2f, paint);
canvas.restore();
}
}
}
static class Heart {
float x, y, speedY, swing, angle, scale = 1f;
int alpha = 255;
Heart(int width) {
x = rnd.nextInt(width);
y = -50;
speedY = 3 + rnd.nextFloat() * 4;
swing = 1 + rnd.nextFloat() * 2;
}
}
}
ParticleSystem / Leonids)引入現成庫,幾行代碼配置發射器、重力、顏色漸變,適合快速交付。
.json;LottieAnimationView,setRepeatCount(-1) 循環播放;heartBitmap,不在 onDraw 解碼;