Android碎裂的粒子效果

作者: zhangke3016 | 来源:发表于2016-12-24 20:06 被阅读3063次

    最近看到一段时间都没怎么更新文章了,一直在学习iOS相关内容。偶然间看到一个碎裂的粒子效果,觉得很有意思,就查了查,参考下网上的思路自己撸了个轮子。

    好了,说了这么多,先看看效果吧~

    粒子破碎效果

    依惯例,先说下行文思路吧,首先我们先简单分析下效果,拆分关注点,粒子效果是怎么产生的?我的解决方案就是先获取当前要碎裂的view的缓存视图,然后根据图片获取各个坐标点的颜色值,在整个DecorView盖上一层视图,这个视图就根据获取的颜色值在要碎裂的view的位置drawCircle,之后变化圆心和半径以及透明度从而产生碎裂效果。那么,我们要解决的问题已经简化为几个点了,看怎么一个一个将其击破。

    一、获取view的视图
    二、获取要碎裂的view的位置以及获取各个位置的颜色值
    三、变化各个属性值产生动画碎裂效果

    一、获取view的视图

    获取view的视图也就是要获取这个视图的截图,有两种方式可以来做:

    1、可以用Canvas来获取Bitmap

    public Bitmap getBitmapFromView(View view) {
        Bitmap bmp = Bitmap.createBitmap(webView.getWidth(),       
        webView.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bmp);
        view.draw(canvas);
        return bmp;
    }
    

    2、用getDrawingCache来获取Bitmap

        private static Bitmap getCacheBitmapFromView(View view) {
            final boolean drawingCacheEnabled = true;
            view.setDrawingCacheEnabled(drawingCacheEnabled);
            view.buildDrawingCache(drawingCacheEnabled);
            final Bitmap drawingCache = view.getDrawingCache();
            Bitmap bitmap;
            if (drawingCache != null) {
                bitmap = Bitmap.createBitmap(drawingCache);
                view.setDrawingCacheEnabled(false);
            } else {
                bitmap = null;
            }
            return bitmap;
        }
    

    通过这两种方式都可以获取这个视图的图片,而为什么我们要获取这个视图的图片呢,因为要根据这个图片来获取各个位置的颜色值,为之后绘制粒子效果服务。

    二、获取要碎裂的view的位置以及获取各个位置的颜色值

    获取view的位置,之前使用过getGlobalVisibleRect方法来获取位置,但很多时候并不是很准确,比如有ActionBar的时候。

    Rect rect = new Rect();
    view.getGlobalVisibleRect(rect);
    

    之后测试使用getLocationInWindow这种方式挺不错,这个方法的官方注释为这样写Computes the coordinates of this view in its window.

     int[] location = new int[2];
     view.getLocationInWindow(location);
     Rect rect = new Rect(location[0],location[1],location[0]+view.getMeasuredWidth(),location[1]+view.getMeasuredHeight());
    

    在获取视图位置之后,我们要获取各个位置的颜色值来绘制在这片区域内,调用bitmap.getPixel方法获取各个位置的颜色值:

    public static Particle[][] generateParticles(Bitmap bitmap, Rect bound) {
            int w = bound.width();
            int h = bound.height();
    
            int partW_Count = w / Particle.PART_WH;
            int partH_Count = h / Particle.PART_WH;
    
            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 * Particle.PART_WH, row * Particle.PART_WH);
                    point = new Point(column, row); //x是列,y是行
                    particles[row][column] = Particle.generateParticle(color, bound, point);
                }
            }
            return particles;
        }
    

    三、变化各个属性值产生动画碎裂效果

    首先我们要在当前视图上覆盖一层产生碎裂效果的视图:

     private void attachToActivity(Activity activity) {
            ViewGroup rootView = (ViewGroup) activity.getWindow().getDecorView();
            ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
    
            rootView.addView(this, lp);
        }
    

    将我们要绘制粒子动画效果的添加进布局视图中,然后我们就可以开始绘制了。
    开启属性动画,根据动画流程变化Particle的相关属性:

        //x值
        public float cx;
        //y值
        public float cy;
        //绘制圆的半径
        public float radius;
        //颜色
        public int color;
        //透明度
        public float alpha;
    

    在自定义视图的onDraw方法,遍历所有我们保存的粒子Particle,改变相关属性值:

    @Override
        protected void onDraw(Canvas canvas) {
            if (mParticleAnimator !=null)
                drawParticle(canvas);
        }
    
        public void drawParticle(Canvas canvas) {
            //动画结束停止
            if(!mParticleAnimator.isRunning()) {
                return;
            }
            for (Particle[] particle : mParticleAnimator.getParticles()) {
                for (Particle p : particle) {
                    p.update((Float) mParticleAnimator.getAnimatedValue());
                    mPaint.setColor(p.color);
                    mPaint.setAlpha((int) (Color.alpha(p.color) * p.alpha));
                    canvas.drawCircle(p.cx, p.cy, p.radius, mPaint);//
                }
            }
            invalidate();
        }
          //更新相关属性值  主要是随机生成x y值以及碎裂大小
          public void update(float factor) {
            cx = cx + factor * random.nextInt(mBound.width()) * (random.nextFloat() - 0.5f);
            cy = cy + factor * (mBound.height()/(random.nextInt(4)+1)) ;
            radius = radius - factor * random.nextInt(3);;
            if (radius<=0)
                radius = 0;
            alpha = 1f - factor;
        }
    

    OK,到这里我们就基本实现了这个碎裂效果,整体注意点基本就这么多,我把它简单封装了下,使用方式也很简单:

      final ParticleView particleAnimator = new ParticleView(MainActivity.this,3000);//3000为动画持续时间 
            particleAnimator.setOnAnimationListener(new ParticleView.OnAnimationListener() {
                @Override
                public void onAnimationStart(View view,Animator animation) {
                    //动画开始
                    view.setVisibility(View.INVISIBLE);
                }
                @Override
                public void onAnimationEnd(View view,Animator animation) {
                    //动画结束
                }
            });
            findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    particleAnimator.boom(v);//开始动画
                }
            });
    

    github地址:ParticleDismissLayout

    相关文章

      网友评论

      • 799917c2dbea:谢谢博主分享,我想问下updata中
        cx = cx + factor * random.nextInt(mBound.width()) * (random.nextFloat() - 0.5f);
        cy = cy + factor * (mBound.height()/(random.nextInt(4)+1)) ;
        这两句的变化规则是啥。
      • 4907f8f7117e:兄弟 写的可以 通俗易懂 条理清晰
      • Thomas__Yang:感谢啊,又开了眼界。不过在ondraw 里面大量的遍历似乎不妥,还有啥更优的法子吗?
      • 3854e67b83db:cpu占用率比较高,可以用gpu渲染吗?
        zhangke3016: @jiaoyang623 可以试一下看看~
      • Tang1024:溜的不行!:smile::+1:

      本文标题:Android碎裂的粒子效果

      本文链接:https://www.haomeiwen.com/subject/lbclvttx.html