ViewExplosion

项目地址:835127729/ViewExplosion
简介:Android 粒子爆炸效果,可以给任意 view 添加该效果
更多:作者   提 Bug   官网   
标签:

特效-

最近在闲逛的时候,发现了一款粒子爆炸特效的控件,觉得比较有意思,效果也不错。 但是代码不好扩展,也就是说如果要提供不同的爆炸效果,需要修改的地方比较多。于是我对源代码进行了一些重构,将爆炸流程和粒子运动分离。 对于源码,大家可以参考以下链接 链接 1 链接 2

上面两套代码,其实结构都是一样的,但是实现的效果不同(其实就是粒子运动的算法不同)。 本篇文章,将给大家介绍粒子爆炸特效的实现方式,替大家理清实现思路。

实现效果如下: 

类设计

类设计图如下: 

ExplosionField,爆炸效果发生的场地,是一个 View。当一个控件需要爆炸时,需要为控件生成一个 ExplosionField,这个 ExplosionField覆盖整个屏幕,于是我们才能看到完整的爆炸效果。

ExplosionAnimator,爆炸动画,其实是一个计时器,继承自 ValueAnimator。1024s 内,完成爆炸动画,每次计时,就更新所有粒子的运动状态。draw()方法是它最重要的方法,也就是使所有粒子重绘自身,从而实现动画效果。

ParticleFactory,是一个抽象类。用于产生粒子数组,不同的 ParticleFactory 可以产生不同类型的粒子数组。

Particle,抽象的粒子类。代表粒子本身,必须拥有的属性包括,当前自己的cx,cy 坐标和颜色 color。必须实现两个方法,draw()方法选择怎么绘制自身(圆形还是方形等),caculate()计算当前时间,自己所处的位置。

控件的使用

控件使用很简单,首先要实现不同的爆炸效果,需要给 ExplosionField 传入不同的 ParticleFactory 工厂,产生不同的粒子。

ExplosionField explosionField = new ExplosionField(this,new FallingParticleFactory());

然后哪个控件需要爆炸效果,就这样添加

explosionField.addListener(findViewById(R.id.text));
explosionField.addListener(findViewById(R.id.layout1));

这样就为两个控件添加了爆炸效果,注意layout1 代表的是一个 viewgroup,那么我们就会为 viewgroup 中的每个 view 添加爆炸效果。 我们可以想象,在 ExplosionField 的构造函数中,传入不同的 ParticleFactory,就可以生成不同的爆炸效果。

爆炸实现思路

1、获取当前控件背景 bitmap

例如,例子中使用的是 imageview,对于这个控件,我提供了一个工具类,可以获得其背景的 Bitmap 对象

public static Bitmap createBitmapFromView(View view) {view.clearFocus();Bitmap bitmap = createBitmapSafely(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888, 1);if (bitmap != null) {synchronized (sCanvas) {Canvas canvas = sCanvas;canvas.setBitmap(bitmap);view.draw(canvas);canvas.setBitmap(null);}}return bitmap;}public static Bitmap createBitmapSafely(int width, int height, Bitmap.Config config, int retryCount) {try {return Bitmap.createBitmap(width, height, config);} catch (OutOfMemoryError e) {e.printStackTrace();if (retryCount > 0) {System.gc();return createBitmapSafely(width, height, config, retryCount - 1);}return null;}}

上面的方法,简而言之,就是将控件的 Bitmap 对象复制了一份,然后返回。 我们知道,bitmap 可以看成是一个像素矩阵,矩阵上面的点,就是一个个带有颜色的像素,于是我们可以获取每个点(未必需要每个)的颜色和位置,组装成一个对象 Particle,这么一来,Particle 就代表带有颜色的点了。

2、将背景 bitmap 转换成 Particle 数组

获取 Bitmap 以后,我们交给 ParticleFactory 进行加工,根据 Bitmap 生产 Particle 数组。

public abstract class ParticleFactory {public abstract Particle[][] generateParticles(Bitmap bitmap, Rect bound);
}

例如我们来看一个简单实现类,也是 gif 图中,第一个下落效果的工厂类

public class FallingParticleFactory extends ParticleFactory{public static final int PART_WH = 8; //默认小球宽高public Particle[][] generateParticles(Bitmap bitmap, Rect bound) {int w = bound.width();//场景宽度int h = bound.height();//场景高度int partW_Count = w / PART_WH; //横向个数int partH_Count = h / PART_WH; //竖向个数int bitmap_part_w = bitmap.getWidth() / partW_Count;int bitmap_part_h = bitmap.getHeight() / partH_Count;Particle[][] particles = new Particle[partH_Count][partW_Count];Point point = null;for (int row = 0; row < partH_Count; row ++) { //行for (int column = 0; column < partW_Count; column ++) { //列//取得当前粒子所在位置的颜色int color = bitmap.getPixel(column * bitmap_part_w, row * bitmap_part_h);float x = bound.left + FallingParticleFactory.PART_WH * column;float y = bound.top + FallingParticleFactory.PART_WH * row;particles[row][column] = new FallingParticle(color,x,y,bound);}}return particles;}}

其中Rect 类型的 bound,是代表原来 View 控件的宽高信息。 根据我们设定的每个粒子的大小,和控件的宽高,我们就可以计算出,有多少个粒子组成这个控件的背景。 我们取得每个粒子所在位置的颜色,位置,用于生产粒子,这就是 FallingParticle。

3、生成爆炸场地,开始爆炸动画流程

爆炸时需要场地的,也就是绘制粒子的地方,我们通过给当前屏幕,添加一个覆盖全屏幕的 ExplosionField 来作为爆炸场地。

public class ExplosionField extends View{.../*** 给 Activity 加上全屏覆盖的 ExplosionField*/private void attach2Activity(Activity activity) {ViewGroup rootView = (ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT);ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);rootView.addView(this, lp);}...
}

爆炸场地添加以后,我们响应控件的点击事件,开始动画 首先是震动动画

 /*** 爆破* @param view 使得该 view 爆破*/public void explode(final View view) {//防止重复点击if(explosionAnimatorsMap.get(view)!=null&&explosionAnimatorsMap.get(view).isStarted()){return;}if(view.getVisibility()!=View.VISIBLE||view.getAlpha()==0){return;}//为了正确绘制粒子final Rect rect = new Rect();view.getGlobalVisibleRect(rect); //得到 view 相对于整个屏幕的坐标int contentTop = ((ViewGroup)getParent()).getTop();Rect frame = new Rect();((Activity) getContext()).getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);int statusBarHeight = frame.top;rect.offset(0, -contentTop - statusBarHeight);//去掉状态栏高度和标题栏高度//震动动画ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f).setDuration(150);animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {Random random = new Random();@Overridepublic void onAnimationUpdate(ValueAnimator animation) {view.setTranslationX((random.nextFloat() - 0.5f) * view.getWidth() * 0.05f);view.setTranslationY((random.nextFloat() - 0.5f) * view.getHeight() * 0.05f);}});animator.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {super.onAnimationEnd(animation);explode(view, rect);//爆炸动画}});animator.start();}

震动动画很简单,就是 x,y 方向上,随机产生一些位移,使原控件发生移动即可。 在震动动画的最后,调用了爆炸动画,于是爆炸动画开始。

private void explode(final View view,Rect rect) {final ExplosionAnimator animator = new ExplosionAnimator(this, Utils.createBitmapFromView(view), rect,mParticleFactory);explosionAnimators.add(animator);explosionAnimatorsMap.put(view, animator);animator.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationStart(Animator animation) {//缩小,透明动画view.animate().setDuration(150).scaleX(0f).scaleY(0f).alpha(0f).start();}@Overridepublic void onAnimationEnd(Animator animation) {view.animate().alpha(1f).scaleX(1f).scaleY(1f).setDuration(150).start();//动画结束时从动画集中移除explosionAnimators.remove(animation);explosionAnimatorsMap.remove(view);animation = null;}});animator.start();}

爆炸动画首先将原控件隐藏。 我们来看爆炸动画的具体实现

public class ExplosionAnimator extends ValueAnimator {...public ExplosionAnimator(View view, Bitmap bitmap, Rect bound,ParticleFactory particleFactory) {mParticleFactory = particleFactory;mPaint = new Paint();mContainer = view;setFloatValues(0.0f, 1.0f);setDuration(DEFAULT_DURATION);mParticles = mParticleFactory.generateParticles(bitmap, bound);}//最重要的方法public void draw(Canvas canvas) {if(!isStarted()) { //动画结束时停止return;}//所有粒子运动for (Particle[] particle : mParticles) {for (Particle p : particle) {p.advance(canvas,mPaint,(Float) getAnimatedValue());}}mContainer.invalidate();}@Overridepublic void start() {super.start();mContainer.invalidate();}
}

实现很简单,就是根据工厂类,生成粒子数组。 而其实质是一个 ValueAnimator,在一定时间内,从 0 数到 1。 然后提供了一个 draw()方法,方法里面调用了每个粒子的 advance()方法,并且传入了当前数到的数字(是一个小数)。 advance()方法里,其实调用了 draw()方法和 caculate()方法。 
上面的实现,其实是一个固定的流程,添加了爆炸场地以后,我们就开始从 0 数到 1,在这个过程中,粒子会根据当前时间,绘制自己的位置,所以粒子的位置,其实是它自己决定的,和流程无关。 也就是说,我们只要用不同的算法,绘制粒子的位置即可,实现了流程和粒子运动的分离。

4、怎么运动?粒子自己最清楚

举个例子,gif 图中,下落效果的粒子是这样运动的

public class FallingParticle extends Particle{static Random random = new Random();float radius = FallingParticleFactory.PART_WH;float alpha = 1.0f;Rect mBound;/*** @param color 颜色* @param x* @param y*/public FallingParticle(int color, float x, float y,Rect bound) {super(color, x, y);mBound = bound;}...protected void caculate(float factor){cx = cx + factor * random.nextInt(mBound.width()) * (random.nextFloat() - 0.5f);cy = cy + factor * random.nextInt(mBound.height() / 2);radius = radius - factor * random.nextInt(2);alpha = (1f - factor) * (1 + random.nextFloat());}
}

caculate(float factor)方法,根据当前时间,计算粒子的下一个位置 我们可以看到,在这个粒子中,cy 也就是竖直方向上是不断增加的,cx 也就是水平方向上,是随机增加或者减少,这样就形成了下落效果。 计算出当前位置以后,粒子就将自己绘制出来

protected void draw(Canvas canvas,Paint paint){paint.setColor(color);paint.setAlpha((int) (Color.alpha(color) * alpha)); //这样透明颜色就不是黑色了canvas.drawCircle(cx, cy, radius, paint);}

怎么扩展?

从上面的代码结构可以看出,爆炸流程和粒子具体运动无关,最重要的是,我们要实现自己的 caculate()方法,决定粒子的运动形态。 而不同的粒子可以由对应的工厂产生,所以要扩展爆炸特性,只需要定义一个粒子类,和生成粒子类的工厂即可。

源码下载 github 地址

Android 粒子爆炸效果,可以给任意 view 添加该效果相关推荐

  1. Android粒子爆炸特效[可用于任意控件]

    小米手机用户可以看到,小米手机在应用卸载时会有一个粒子爆炸的特效效果,对此类动画效果垂涎已久,奈何一直没有机会用.正好最近项目里需要用到粒子爆炸的特效,于是便抽时间自己也试着仿写了一个效果出来. 先看 ...

  2. 自定义ListView实现任意View跑马灯效果

    自定义ListView实现任意View跑马灯效果 标签(空格分隔): 开源项目 看图 话不多说,先来看下大图效果吧,这里的GIF录制有点渣,不过真实的跑出来的效果还是挺不错的. 前言 最近项目中会加入 ...

  3. android 粒子爆炸特效

    先上图: 这是一个高级UI特效,是个动画. 完成这个动画只要3步: 1.控件完成振动效果动画. 2.控件振动动画完成后消失,然后将控件转换成Bitmap. 3.Bitmap完成粒子爆炸特效. 其实完成 ...

  4. android 桌面动画,Android 如何在Launcher的桌面滑动时添加动画效果? M

    正文 目前的Launcher桌面滑动时,是没有动画的.如何在Lancher的桌面滑动时添加动画效果?Demo: 请修改Workspace.java的screenScrolled方法,如下: @Over ...

  5. ajax上传等待效果,ajax等待服务器响应添加等待效果

    ajax等待服务器响应添加等待效果 内容精选 换一换 删除备份.删除操作为异步操作,删除操作会根据后台执行任务的情况进行排队,所以不会立即完成删除,需要通过不断查询删除任务信息获取删除结果,时间最长耗 ...

  6. 第5章第3节:如何给幻灯片中的元素添加交互效果 [PowerPoint精美幻灯片实战教程]

    本节演示如何给幻灯片添加交互效果,也就是当点击了幻灯片中的某个对象之后,才会播放指定的动画效果. 在选择需要添加动画效果的对象之后,点击此处的下拉箭头,查看更多的动画效果. 点击底部的更多进入效果命令 ...

  7. VisionPro 定位添加瞄准效果

    VisionPro 定位添加瞄准效果 文章目录 VisionPro 定位添加瞄准效果 前言 一.效果展示 二.实现步骤 1.初始化 2.运行按钮 3.复合图形移动显示 总结 前言 图案定位其实就是在图 ...

  8. 第9章第7节:给目录页幻灯片中的元素添加动画效果 [PowerPoint精美幻灯片实战教程]

    在完成目录页的制作之后,现在来给幻灯片中的元素添加动画效果.首先选择需要添加动画效果的对象. 点击动画选项卡,显示动画功能面板. 然后给所选对象添加名为淡化的动画效果. 将动画的开始方式设置为上一动画 ...

  9. android view爆炸效果,Android 显示view的粒子爆炸/绽放效果

    照例先上图 这个库做了什么? 它可以以粒子的形式显示任何view的粒子动画效果,你可以下载DEMO来查看效果 功能 支持任何view 可灵活配置粒子大小和形状 可灵活配置粒子动画 形状 在该库中,支持 ...

最新文章

  1. R语言使用integrate函数进行函数积分计算实战
  2. hexo d 部署博客时出错
  3. 调用API的SDK相关知识:实现回调函数.
  4. java -cp ***.jar WordCount 无法找到类名解决方案记录
  5. 计算机视觉会议与专家(重排版)
  6. 表单校验---struts2
  7. 深度学习之神经网络的结构
  8. Jsp Servlet Mysql实现的学生成绩管理系统
  9. 洛谷P3402 【模板】可持久化并查集
  10. 大咖说中台 | 中台不是“银弹”!
  11. iconfont 阿里巴巴矢量图标库 在线引入图标
  12. 玩转GD32F3x0开发板 (二)
  13. graphene-django开发实践——登录为例
  14. 2021年高处安装、维护、拆除证考试及高处安装、维护、拆除复审模拟考试
  15. Proteus仿真——常用元件
  16. 展示正在活动时间内的活动,过期活动不显示
  17. 《Windows核心编程》读书笔记二十五章 未处理异常,向量化异常处理与C++异常
  18. GSM 03.38 from Wikipedia
  19. matlab变量及操作
  20. 一种网络用户行为日志自动获取方法

热门文章

  1. 1974: 两点之间的距离(结构体专题)
  2. 通过从代码层面分析Linux内核启动来探知操作系统的启动过程
  3. 非标行业的类标准产品经验
  4. HDFS上传文件报错org.apache.hadoop.fs.ChecksumException: Checksum error: file:/hyk/data/hyk.txt
  5. Qt之网络编程错误总结
  6. Linux作业 北京各监测站的PM2.5浓度
  7. web audio音效播放器/音乐播放器
  8. word文档中图片不显示的问题以及解决
  9. 录屏大师怎么用 录屏大师使用教程
  10. 【Linux_选择题】(D26 0525)