自定义粒子破碎效果

来源:互联网 发布:fpga硬件编程语言 编辑:程序博客网 时间:2024/04/27 08:07

自定义粒子破碎效果图:

本文内容仿至阿曌博客,并在此基础上稍作修改,纯粹学习目的,更多详情请查看原文

个人觉得粒子破碎的核心就是怎样把一张图片分解成粒子,并让其呈现破碎四散的效果,下面说说实现过程:

  1. 我们需要拿到图片对象,因为我们是要让整个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());    }

最关键的部分上面已经介绍完了,下面说说我在实现效果过程中觉得有必要记录的知识点:

  1. 继承ViewGroup 的view通常情况下不会调用onDraw方法,原因, 解决办法:

    1,在构造函数里面,给其设置一个颜色,如#00000000。

    if(getBackground()==null){
    setBackgroundColor(Color.WHITE);
    }

    2,在构造函数里面,调用setWillNotDraw(false),去掉其WILL_NOT_DRAW flag。

  2. 属性动画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
原创粉丝点击