自定义粒子破碎效果
来源:互联网 发布:fpga硬件编程语言 编辑:程序博客网 时间:2024/04/27 08:07
自定义粒子破碎效果图:
本文内容仿至阿曌博客,并在此基础上稍作修改,纯粹学习目的,更多详情请查看原文
个人觉得粒子破碎的核心就是怎样把一张图片分解成粒子,并让其呈现破碎四散的效果,下面说说实现过程:
- 我们需要拿到图片对象,因为我们是要让整个view都呈现破碎的效果,那么就直接把view复制成一张图片
/** * 把当前view复制成一张图片,并绘制出来 * @param view * @return */private Bitmap CopyView(View view) { Bitmap bitmap=Bitmap.createBitmap(view.getMeasuredWidth(),view.getMeasuredHeight(),Config.ARGB_8888); canvas.setBitmap(bitmap); view.draw(canvas); return bitmap; }
2 . 拿到图片后,把图片裁剪成若干个粒子,每个粒子都保存相应的信息(中心点,半径,颜色,透明度),并把粒子保存到一个二维数组里
/** * 把当前复制过来的view图片裁剪成颗粒 * @param copyView * @param rect 包裹view的矩形 */ private Granule[][] DivisionView(Bitmap copyView, Rect rect) { int color; Point point; //当前view宽高可以裁剪成多少粒子 int countW=rect.width()/Granule.GranuleWH; int countH=rect.height()/Granule.GranuleWH; int bitmap_part_w = copyView.getWidth() / countW; int bitmap_part_h = copyView.getHeight() / countH; //二位数组包含该view图片所有的粒子信息 Granule[][]granules=new Granule[countH][countW];//先行后列 for(int row=0;row<countH;row++){//行 for(int column=0;column<countW;column++){//列 //获取每个粒子的颜色 color=copyView.getPixel(column*bitmap_part_w,row*bitmap_part_h);//竖 //记录每个点 point=new Point(column,row); //记录粒子信息,并返回一个粒子对象 granules[row][column]=Granule.SetGranuleAttribute(color, rect, point); } } return granules; }
3 . 上面我们已经把图片裁剪成了粒子,呈现破碎效果就只需要不断的更改每个粒子的信息(中心点,半径,颜色,透明度)就可以了,修改粒子信息需要一个动态的值,最合适的就是通过动画来实现,通过继承属性 ValueAnimator,设置setFloatValues(0f,1f);表示从0平滑过渡到1,然后我们通过getAnimatedValue()拿到实时的过渡值,通过这个值来修改信息,即可实现破碎的效果;
public void ondraw(Canvas canvas){ //判断动画是否开始 if(!isStarted()){ return; } for(Granule[]granule:granules){ for(Granule g:granule){ //修改粒子信息 g.ChangeGranuleAttribute((float) getAnimatedValue()); //把粒子修改成圆形绘制出来 paint.setColor(g.color); // paint.setAlpha((int) (255 * g.alpha)); //不会出现透明度的渐变效果 paint.setAlpha((int) (Color.alpha(g.color) * g.alpha)); canvas.drawCircle(g.centerX,g.centerY, g.radius,paint); } } view.invalidate(); }/** * 修改粒子属性 * @param factor */ public void ChangeGranuleAttribute(float factor){ //中心点在原view矩形内随机 centerX=centerX+factor*random.nextInt(rect.width())* (random.nextFloat() - 0.5f);//nextFloat() 0-1内随机 centerY=centerY+factor*random.nextInt(rect.height())* (random.nextFloat() - 0.5f); //半径慢慢变小 radius=radius-factor*random.nextInt(2); //透明度随之变低 alpha = (1f - factor) * (1 + random.nextFloat()); }
最关键的部分上面已经介绍完了,下面说说我在实现效果过程中觉得有必要记录的知识点:
继承ViewGroup 的view通常情况下不会调用onDraw方法,原因, 解决办法:
1,在构造函数里面,给其设置一个颜色,如#00000000。
if(getBackground()==null){
setBackgroundColor(Color.WHITE);
}2,在构造函数里面,调用setWillNotDraw(false),去掉其WILL_NOT_DRAW flag。
属性动画ValueAnimator的使用
源代码:
GranuleExplodeView:
import java.util.ArrayList;import java.util.List;import android.animation.Animator;import android.animation.AnimatorListenerAdapter;import android.animation.ValueAnimator;import android.content.Context;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Point;import android.graphics.Rect;import android.graphics.Bitmap.Config;import android.util.AttributeSet;import android.view.View;import android.widget.AbsListView;import android.widget.AdapterView;import android.widget.AdapterView.OnItemClickListener;import android.widget.LinearLayout;import android.view.View.OnClickListener;;public class GranuleExplodeView extends LinearLayout implements OnClickListener, OnItemClickListener{ private Canvas canvas; /** 包含了粒子信息的粒子集合*/ private Granule [][]granules; /** 动画集合*/ private List<GranuleAnimation> animations; public GranuleExplodeView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } public GranuleExplodeView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public GranuleExplodeView(Context context) { super(context); init(); } private void init() {// if(getBackground()==null){// setBackgroundColor(Color.WHITE);// } setWillNotDraw(false); setOrientation(VERTICAL); canvas=new Canvas(); animations=new ArrayList<GranuleAnimation>(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); MeasureChild(this); } private void MeasureChild(ViewGroup viewGroup) { int childcount=viewGroup.getChildCount(); for(int i=0;i<childcount;i++){ View view=viewGroup.getChildAt(i); if(view instanceof ViewGroup){ if(view instanceof AbsListView){ ((AbsListView) view).setOnItemClickListener(this); }else { MeasureChild(((ViewGroup) view)); } }else { //给每个子view都添加监听 view.setClickable(true); view.setOnClickListener(this); } } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); for(GranuleAnimation animation:animations){ animation.ondraw(canvas); } } @Override public void onClick(View v) { CopyDivisionView(v); } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { CopyDivisionView(view); } /** * 把view复制并分割成若干颗粒 * @param view */ private void CopyDivisionView(final View view) { Rect rect=new Rect(); //http://www.cnblogs.com/ai-developers/p/4413585.html //getGlobalVisibleRect方法的作用是获取视图在屏幕坐标中的可视区域 //getLocalVisibleRect的作用是获取视图本身可见的坐标区域,坐标以自己的左上角为原点(0,0) view.getGlobalVisibleRect(rect); //把view图片裁剪,记录每个粒子信息 并保存在一个二维数组里 granules=DivisionView(CopyView(view),rect); //开启一个动画 GranuleAnimation granuleAnimation=new GranuleAnimation(this, granules); animations.add(granuleAnimation); granuleAnimation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { //让原有的view隐藏起来 view.animate().alpha(0f).setDuration(5).start(); } @Override public void onAnimationEnd(Animator animation) { //动画结束的时候可以去刷新,这里就直接还原了 view.animate().alpha(1f).setDuration(150).start(); //移除动画 animations.remove(animation); animation=null; } }); granuleAnimation.start(); } /** * 把当前复制过来的view图片裁剪成颗粒 * @param copyView * @param rect 包裹view的矩形 */ private Granule[][] DivisionView(Bitmap copyView, Rect rect) { int color; Point point; //当前view宽高可以裁剪成多少粒子 int countW=rect.width()/Granule.GranuleWH; int countH=rect.height()/Granule.GranuleWH; int bitmap_part_w = copyView.getWidth() / countW; int bitmap_part_h = copyView.getHeight() / countH; //二位数组包含该view图片所有的粒子信息 Granule[][]granules=new Granule[countH][countW];//先行后列 for(int row=0;row<countH;row++){//行 for(int column=0;column<countW;column++){//列 //获取每个粒子的颜色 color=copyView.getPixel(column*bitmap_part_w,row*bitmap_part_h);//竖 //记录每个点 point=new Point(column,row); //记录粒子信息,并返回一个粒子对象 granules[row][column]=Granule.SetGranuleAttribute(color, rect, point); } } return granules; } /** * 把当前view复制成一张图片,并绘制出来 * @param view * @return */ private Bitmap CopyView(View view) { Bitmap bitmap=Bitmap.createBitmap(view.getMeasuredWidth(),view.getMeasuredHeight(),Config.ARGB_8888); canvas.setBitmap(bitmap); view.draw(canvas); return bitmap; } class GranuleAnimation extends ValueAnimator{ private View view; private Granule[][]granules; private Paint paint; public GranuleAnimation(View view,Granule[][]granules) { paint=new Paint(); this.view=view; this.granules=granules; setFloatValues(0f,1f); setDuration(1500); } @Override public void start() { super.start(); //会触发ondraw view.invalidate(); } public void ondraw(Canvas canvas){ //判断动画是否开始 if(!isStarted()){ return; } for(Granule[]granule:granules){ for(Granule g:granule){ //修改粒子信息 g.ChangeGranuleAttribute((float) getAnimatedValue()); //把粒子修改成圆形绘制出来 paint.setColor(g.color); // paint.setAlpha((int) (255 * g.alpha)); //不会出现透明度的渐变效果 paint.setAlpha((int) (Color.alpha(g.color) * g.alpha)); canvas.drawCircle(g.centerX,g.centerY, g.radius,paint); } } view.invalidate(); } }}
Granule:
import java.util.Random;import android.graphics.Point;import android.graphics.Rect;/** * 粒子颗粒(圆形) */public class Granule { /** 默认粒子的宽高*/ static final int GranuleWH=8; /** 每粒颗粒的中心点X*/ float centerX; /** 每粒颗粒的中心点Y*/ float centerY; /** 每粒颗粒的透明度,默认为1f,会随时间变为0f , 0为完全透明,255为全显示*/ float alpha=1f; /** 每粒颗粒的圆半径*/ float radius; /** 每粒颗粒的包裹矩形*/ Rect rect; /** 每粒颗粒的颜色*/ int color; /** 每粒颗粒扩散的随机值*/ Random random=new Random(); /** * 设置每个粒子的属性并返回该粒子对象 * @param color * @param rect * @param point */ public static Granule SetGranuleAttribute(int color,Rect rect,Point point){ Granule granule=new Granule(); granule.centerX=rect.left+GranuleWH*point.x; granule.centerY=rect.top+GranuleWH*point.y; granule.alpha=1f; granule.color=color; granule.radius=GranuleWH; granule.rect=rect; return granule; } /** * 修改粒子属性 * @param factor */ public void ChangeGranuleAttribute(float factor){ //中心点在原view矩形内随机 centerX=centerX+factor*random.nextInt(rect.width())* (random.nextFloat() - 0.5f);//nextFloat() 0-1内随机 centerY=centerY+factor*random.nextInt(rect.height())* (random.nextFloat() - 0.5f); //半径慢慢变小 radius=radius-factor*random.nextInt(2); //透明度随之变低 alpha = (1f - factor) * (1 + random.nextFloat()); }}
GranuleExplodeActivity:
import java.util.ArrayList;import java.util.HashMap;import com.example.mytoolutils.R;import android.app.Activity;import android.os.Bundle;import android.widget.GridView;import android.widget.SimpleAdapter;public class GranuleExplodeActivity extends Activity { //生成动态数组,并且转入数据 private ArrayList<HashMap<String, Object>> lstImageItem = new ArrayList<HashMap<String, Object>>(); private SimpleAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_granule_explode); SetData(); GridView gridView=(GridView) findViewById(R.id.gridview); adapter=new SimpleAdapter(this,lstImageItem, R.layout.activity_gridview_item, new String[]{"ItemImage","ItemText"}, new int[] {R.id.imagviewgridview,R.id.textviewgridview}); gridView.setAdapter(adapter); } private void SetData() { for(int i=0;i<20;i++) { HashMap<String, Object> map = new HashMap<String, Object>(); map.put("ItemImage", R.drawable.yueyunp);//添加图像资源的ID map.put("ItemText", "NO."+String.valueOf(i));//按序号做ItemText lstImageItem.add(map); } }}
R.layout.activity_granule_explode:
<com.example.mytoolutils.explode.GranuleExplodeView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.mytoolutils.explode.GranuleExplodeActivity" > <GridView android:id="@+id/gridview" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:horizontalSpacing="10dp" android:listSelector="@color/transparent" android:numColumns="4" android:padding="10dp" android:stretchMode="columnWidth" android:verticalSpacing="10dp" > </GridView></com.example.mytoolutils.explode.GranuleExplodeView>
0 0
- 自定义粒子破碎效果
- 学习ExplosionField之粒子破碎效果
- 【Android效果集】学习ExplosionField之粒子破碎效果
- 【Android效果集】学习ExplosionField之粒子破碎效果
- Android粒子破碎效果(2)——实现多种破碎效果之ParticleSmasher
- Android粒子破碎效果(1)——开源项目ExplosionField代码分析
- Android 玻璃破碎效果
- cocos2d-x自定义五角星粒子效果
- 6 cocos2dx粒子效果,类图关系,系统原生粒子和自定义粒子效果,粒子编译器软件,爆炸粒子效果,烟花效果,火焰效果,流星效果,漩涡粒子效果,雪花效果,烟雾效果,太阳效果,下雨效果
- 粒子效果
- 粒子效果
- 粒子效果
- 粒子效果
- 粒子效果
- 粒子效果
- UE4物体下落破碎效果
- android通过自定义view实现粒子效果展示
- android自定义view粒子效果之雨(not surfaceview)
- 关于block传值的问题心得
- VLC web 插件javascript常用接口及属性
- vmware虚拟机从A点恢复到之前的snapshot点之后,A点的数据还可以拿到
- [Source/wheels]foreach()函数
- Buddy/Sponsor培训•信任的构建
- 自定义粒子破碎效果
- Keil 编译器结果解释
- java实现了简单的Echo服务程序分服务器和客户端
- Android 侧滑删除 菜单.
- Spring IOC容器实现
- 多和系统下如何指定进程运行的位置(树莓派、NanoPi)
- 大数据技术总结
- 链表学习(C语言实现)
- 5万无一失:网站的高可用架构