Android 爆炸粒子动画-参考ExplosionField开源项目

本文介绍了一个基于Android平台的自定义爆炸动画实现方案。利用贝塞尔曲线作为粒子运动轨迹,通过ValueAnimator实现粒子从中心向外扩散的动画效果。文章提供了完整的代码示例,包括自定义View的绘制逻辑及动画控制器的核心实现。

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

Android 爆炸粒子动画-参考ExplosionField开源项目

explosion开源项目地址:https://github.com/ChanJLee/ExplosionField

由于没有理解到explosionField开源项目里的粒子爆炸后运动曲线计算公式,我这里使用了贝塞尔曲线作为粒子运动轨迹

在我的APP中应用效果图如下:

这里写图片描述

以下为此动画的核心类,继承自ValueAnimator

粒子在动画时长内沿着贝塞尔曲线运动:

这里写图片描述

曲线由起点,终点,和控制点决定,计算公式为:

这里写图片描述

这里,P0为起点,P1为控制点,P2为终点,t为属性动画的属性值,在动画时长内由0-1变化。


package com.konka.peter.bookentry.lib;


import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.view.View;
import android.view.animation.AccelerateInterpolator;

//我自己的工具类,这里只用到了dp与px单位换算方法
import com.konka.peter.bookentry.util.Util;

import java.util.Random;

/**
 * 类描述 :自定义爆炸动画类,CircleView中使用
 * @author 王春涛
 * @version 1.0.0
 */
public class ExplosionAnimator extends ValueAnimator  {

    //动画时长
    private static final int DURATION=900;
    //画笔
    private Paint paint;
    //所有爆炸后的粒子
    private Particle[] particles;
    //动画区域
    private Rect rect;
    //动画容器View
    private View view;
    //初始粒子数量num*num
    private int num=6;
    //每颗粒子半径
    private static final float R= Util.dp2Px(2);
    //随机变量
    private Random random;
    //粒子颜色
    private int [] colors={0xf5f7fa,0xeaf2bf,0xf5f5eb,0xd1e69c,0xffffff};



    public ExplosionAnimator(View view,Rect rect){
        paint=new Paint();
        this.rect=new Rect(rect);
        //根据动画区域大小,计算粒子数量
        num=Util.px2Dp(rect.right-rect.left)/12;
        if(num<2){
            num=2;
        }

        particles=new Particle[num*num];
        random=new Random(System.currentTimeMillis());

        //初始化粒子
        for(int i=0;i<num;i++){
            for(int j=0;j<num;j++){
                int color=colors[random.nextInt(colors.length)];
                particles[i*num+j]=initParticle(color);
            }
        }

        this.view=view;

        //设置动画取值范围
        setFloatValues(0f,1f);
        //动画速率曲线
        setInterpolator(new AccelerateInterpolator(0.6f));
        setDuration(DURATION);

    }



    /**
     * 方法描述:   绘制每一颗粒子
     * @param      canvas  画布
     * @return     boolean
     */
    public boolean draw(Canvas canvas){

        for (Particle particle:particles){
            //根据当前属性值,定位粒子在贝塞尔曲线上的坐标,getAnimatedValue获取当前动画属性值
            particle.update((float) getAnimatedValue());
            //绘制粒子
            if(particle.alpha>0f){
                paint.setColor(particle.color);
                paint.setAlpha((int) particle.alpha);
                canvas.drawCircle(particle.x,particle.y,particle.r,paint);
            }
        }

        //绘制完,刷新view显示,此时动画与父View之间实现了串联互动
        view.invalidate();
        return true;
    }



 /**
     * 方法描述:   动画开始,刷新页面
     * @param      
     * @return     
     */

    @Override
    public void start() {
        super.start();
        view.invalidate();
    }



    /**
     * 方法描述:   初始化一颗粒子
     * @param      color 粒子颜色
     * @return     Particle 粒子
     */
    public Particle initParticle(int color){
        //自定义的粒子类
        Particle particle=new Particle();
        particle.color=color;
        particle.r=R;
        //start小于0.5,粒子向右运动,大于等于0.5,粒子向左运动
        float start=random.nextFloat();
        //粒子轨迹终点的随机偏移
        float end=random.nextFloat();
        //每颗粒子轨迹的起点都是固定的
        particle.start_x=(rect.right+rect.left)/2;
        particle.start_y=(rect.bottom+rect.top)/2;
        //粒子终点则随机产生计算
        if(start<0.5){       //向右
            particle.end_x=(rect.right+rect.left)/2+(rect.right-rect.left)*end;
            particle.end_y=rect.bottom+20*end;
        }else {              //向左
            particle.end_x=(rect.right+rect.left)/2-(rect.right-rect.left)*(1-end);
            particle.end_y=rect.bottom-20*(1-end);

        }

        //贝塞尔曲线的控制点,由轨迹起点,终点以及0.7和3两个可变数决定
        particle.control_x=particle.start_x+0.7f*(particle.end_x-particle.start_x);
        particle.control_y=particle.start_y-3*random.nextInt((int) (particle.end_y-particle.start_y));

        return particle;
    }



    /**
     * 类描述:   一颗粒子的实体类
     *
     */
    private class Particle{
        //透明度
        float alpha;
        //颜色
        int color;
        //x坐标
        float x;
        //y坐标
        float y;
        //半径
        float r;

        //运行轨迹开始坐标
        float start_x;
        float start_y;
        //运行轨迹结束坐标
        float end_x;
        float end_y;

        //贝塞尔曲线控制点坐标
        float control_x;
        float control_y;


        /**
         * 方法描述:   初始化一颗粒子
         * @param      index 此刻动画的属性值
         * @return     Particle 粒子
         */
        public void update(float index){

            //贝塞尔曲线计算此刻粒子坐标,根据贝塞尔曲线公式
            x=(1-index)*(1-index)*start_x+2*index*(1-index)*control_x+index*index*end_x;
            y=(1-index)*(1-index)*start_y+2*index*(1-index)*control_y+index*index*end_y;
            //透明度
            if(index<0.8){
                alpha=255;
            }else {
                alpha=255*(-5*index+5);
            }

        }

    }



}

接下来我们在一个自定义View里面使用以上动画:


package com.konka.peter.bookentry.lib;

import android.animation.Animator;
import android.content.Context;
import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.Rect;

import android.view.View;



/**
 * 类描述 :自定义View
 * @author 王春涛
 * @version 1.0.0
 */



public class CircleView extends View {



    //粒子爆炸动画
    private  ExplosionAnimator explosionAnimator;


    public CircleView(Context context) {
        super(context);
        //动画开始
        startExplosionAnim();

    }

    public CircleView(Context context, AttributeSet attrs) {
        super(context, attrs);
        //动画开始
        startExplosionAnim();
    }

    public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        //动画开始
        startExplosionAnim();

    }





    /**
     * 方法描述:   重写绘制方法,在这里绘制爆炸过程的每一帧
     * @param      canvas 画布
     * @return     void
     *
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        explosionAnimator.draw(canvas);

    }






    private void startExplosionAnim(){
        //动画显示区域
        Rect rect=new Rect(0,0,200,200);
        explosionAnimator=new ExplosionAnimator(this,rect);

        explosionAnimator.start();

    }



}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值