miui卸载爆炸效果

来源:互联网 发布:阿里云dns 多ip 编辑:程序博客网 时间:2024/04/30 18:15



package com.example.sss;import android.annotation.SuppressLint;import android.app.Activity;import android.os.Bundle;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.view.ViewGroup;public class MainActivity extends Activity {    private ExplosionField mExplosionField;    @SuppressLint("ResourceAsColor")@Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mExplosionField = ExplosionField.attach2Window(this);        addListener(findViewById(R.id.root));                    }    /**     * 为root中除了ViewGroup的控件都添加点击事件,点击后执行爆炸效果     * @param root     */    private void addListener(View root) {        if (root instanceof ViewGroup) {            ViewGroup parent = (ViewGroup) root;            for (int i = 0; i < parent.getChildCount(); i++) {                addListener(parent.getChildAt(i));            }        } else {            root.setClickable(true);            root.setOnClickListener(new View.OnClickListener() {                @Override                public void onClick(View v) {                    mExplosionField.explode(v);                    v.setOnClickListener(null);                }            });        }    }    public void click(View v){        View root = findViewById(R.id.root);        reset(root);        addListener(root);        mExplosionField.clear();    }     private void reset(View root) {            if (root instanceof ViewGroup) {            ViewGroup parent = (ViewGroup) root;            for (int i = 0; i < parent.getChildCount(); i++) {                reset(parent.getChildAt(i));            }        } else {            root.setScaleX(1);            root.setScaleY(1);            root.setAlpha(1);        }    }}

<?xml version="1.0" encoding="utf-8"?><LinearLayout 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"    android:orientation="vertical"    tools:context=".MainActivity"    android:background="#fff"    >    <RelativeLayout        android:layout_width="match_parent"        android:layout_height="48dp"        android:background="@color/colorPrimary"        >        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="标题"            android:textSize="20sp"            android:textColor="#fff"            android:layout_centerInParent="true"/>        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="返回"            android:layout_centerVertical="true"            android:textColor="#fff"            />    </RelativeLayout>    <LinearLayout     android:id="@+id/root"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:gravity="center_horizontal"    android:orientation="vertical"    android:paddingBottom="@dimen/activity_vertical_margin"    android:paddingLeft="@dimen/activity_horizontal_margin"    android:paddingRight="@dimen/activity_horizontal_margin"    android:paddingTop="@dimen/activity_vertical_margin"    tools:context=".MainActivity">    <LinearLayout        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_marginTop="48dp"        android:orientation="horizontal">        <ImageView            android:layout_width="0dp"            android:layout_height="wrap_content"            android:layout_weight="1"            android:clickable="true"            android:src="@drawable/p1" />        <ImageView            android:layout_width="0dp"            android:layout_height="wrap_content"            android:layout_weight="1"            android:clickable="true"            android:src="@drawable/p6" />        <ImageView            android:layout_width="0dp"            android:layout_height="wrap_content"            android:layout_weight="1"            android:src="@drawable/p2" />    </LinearLayout>    <LinearLayout        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_marginTop="48dp"        android:orientation="horizontal">        <ImageView            android:layout_width="0dp"            android:layout_height="wrap_content"            android:layout_weight="1"            android:clickable="true"            android:src="@drawable/p4" />        <ImageView            android:layout_width="0dp"            android:layout_height="wrap_content"            android:layout_weight="1"            android:src="@drawable/p5" />        <ImageView            android:layout_width="0dp"            android:layout_height="wrap_content"            android:layout_weight="1"            android:src="@drawable/p3" />    </LinearLayout>    <TextView        android:layout_width="match_parent"        android:gravity="center"        android:layout_marginTop="48dp"        android:text="click to destroy"        android:layout_height="wrap_content" /></LinearLayout>        <Button         android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="重置"        android:onClick="click"/></LinearLayout>

/* * Copyright (C) 2015 tyrantgit * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com.example.sss;import android.animation.Animator;import android.animation.AnimatorListenerAdapter;import android.animation.ValueAnimator;import android.app.Activity;import android.content.Context;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Rect;import android.util.AttributeSet;import android.view.View;import android.view.ViewGroup;import android.view.Window;import java.util.ArrayList;import java.util.Arrays;import java.util.List;import java.util.Random;/** * 原理:  在activity上覆盖一个ExplosionField控件,在该控件上绘制爆照粒子 * @author young * */public class ExplosionField extends View {//一个activity中只有一个ExplosionField,但可以同时在ExplosionField上绘制多个爆炸效果    private List<ExplosionAnimator> mExplosions = new ArrayList<>();    private int[] mExpandInset = new int[2];    public ExplosionField(Context context) {        super(context);        init();    }        public ExplosionField(Context context, AttributeSet attrs) {        super(context, attrs);        init();    }    public ExplosionField(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        init();    }    private void init() {        Arrays.fill(mExpandInset, Utils.dp2Px(32));    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        for (ExplosionAnimator explosion : mExplosions) {            explosion.draw(canvas);        }    }    public void expandExplosionBound(int dx, int dy) {        mExpandInset[0] = dx;        mExpandInset[1] = dy;    }    public void explode(Bitmap bitmap, Rect bound, long startDelay, long duration) {        final ExplosionAnimator explosion = new ExplosionAnimator(this, bitmap, bound);        explosion.addListener(new AnimatorListenerAdapter() {            @Override            public void onAnimationEnd(Animator animation) {                mExplosions.remove(animation);            }        });        explosion.setStartDelay(startDelay);        explosion.setDuration(duration);        mExplosions.add(explosion);        explosion.start();    }    /**     * 执行爆炸     * @param view     */    public void explode(final View view) {        Rect r = new Rect();        view.getGlobalVisibleRect(r);        int[] location = new int[2];        getLocationOnScreen(location);        r.offset(-location[0], -location[1]);        r.inset(-mExpandInset[0], -mExpandInset[1]);        int startDelay = 100;        //爆炸前的抖动效果        ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f).setDuration(150);        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            Random random = new Random();            @Override            public 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.start();        //抖动结束后用150毫秒把view缩小到看不到        view.animate().setDuration(150).setStartDelay(startDelay).scaleX(0f).scaleY(0f).alpha(0f).start();        explode(Utils.createBitmapFromView(view), r, startDelay, ExplosionAnimator.DEFAULT_DURATION);    }    public void clear() {        mExplosions.clear();        invalidate();    }    /**     * 把该View添加到Activity中     * @param activity     * @return     */    public static ExplosionField attach2Window(Activity activity) {    //rootView是一个FrameLayout,也可以使用activityactivity.getWindow().getDecorView()来获取,获取到的是用户通过setContentView设置的 布局 的 父布局        ViewGroup rootView = (ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT);        System.out.println("rootview = "+rootView);        ExplosionField explosionField = new ExplosionField(activity);        //添加进去        rootView.addView(explosionField, new ViewGroup.LayoutParams(                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));        return explosionField;    }}

/* * Copyright (C) 2015 tyrantgit * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.example.sss;import android.animation.ValueAnimator;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Rect;import android.view.View;import android.view.animation.AccelerateInterpolator;import android.view.animation.Interpolator;import java.util.Random;public class ExplosionAnimator extends ValueAnimator {    static long DEFAULT_DURATION = 0x400;    private static final Interpolator DEFAULT_INTERPOLATOR = new AccelerateInterpolator(0.6f);    private static final float END_VALUE = 1.4f;    private static final float X = Utils.dp2Px(5);    private static final float Y = Utils.dp2Px(20);    private static final float V = Utils.dp2Px(2);    private static final float W = Utils.dp2Px(1);    private Paint mPaint;    private Particle[] mParticles;    private Rect mBound;    private View mContainer;    public ExplosionAnimator(View container, Bitmap bitmap, Rect bound) {        mPaint = new Paint();        mBound = new Rect(bound);        int partLen = 15;        mParticles = new Particle[partLen * partLen];        Random random = new Random(System.currentTimeMillis());        //把图片横向分成17份,每份的宽度        int w = bitmap.getWidth() / (partLen + 2);        //把图片纵向分成17份,每份的宽度        int h = bitmap.getHeight() / (partLen + 2);              //总共分成了17*17块,从图片中每块(不包含边界块)的顶点的像素取出颜色后创建该颜色的粒子,然后保存到一维数组mParticles中        for (int i = 0; i < partLen; i++) {            for (int j = 0; j < partLen; j++) {                mParticles[(i * partLen) + j] = generateParticle(bitmap.getPixel((j + 1) * w, (i + 1) * h), random);            }        }        mContainer = container;        setFloatValues(0f, END_VALUE);        setInterpolator(DEFAULT_INTERPOLATOR);        setDuration(DEFAULT_DURATION);    }    /**     * 生成粒子     * @param color     * @param random     * @return     */    private Particle generateParticle(int color, Random random) {        Particle particle = new Particle();        particle.color = color;        particle.radius = V;        if (random.nextFloat() < 0.2f) {            particle.baseRadius = V + ((X - V) * random.nextFloat());        } else {            particle.baseRadius = W + ((V - W) * random.nextFloat());        }        float nextFloat = random.nextFloat();        particle.top = mBound.height() * ((0.18f * random.nextFloat()) + 0.2f);        particle.top = nextFloat < 0.2f ? particle.top : particle.top + ((particle.top * 0.2f) * random.nextFloat());        particle.bottom = (mBound.height() * (random.nextFloat() - 0.5f)) * 1.8f;        float f = nextFloat < 0.2f ? particle.bottom : nextFloat < 0.8f ? particle.bottom * 0.6f : particle.bottom * 0.3f;        particle.bottom = f;        particle.mag = 4.0f * particle.top / particle.bottom;        particle.neg = (-particle.mag) / particle.bottom;        f = mBound.centerX() + (Y * (random.nextFloat() - 0.5f));        particle.baseCx = f;        particle.cx = f;        f = mBound.centerY() + (Y * (random.nextFloat() - 0.5f));        particle.baseCy = f;        particle.cy = f;        particle.life = END_VALUE / 10 * random.nextFloat();        particle.overflow = 0.4f * random.nextFloat();        particle.alpha = 1f;        return particle;    }    /*     * 该属性动画只是起到一个计时作用,与爆炸效果没有其他联系。若动画时间还没结束,则依次计算每个粒子当前的各属性值(坐标,半径),然后依次绘制每个粒子     * (  canvas.drawCircle(particle.cx, particle.cy, particle.radius, mPaint);  ),     * 然后调用mContainer.invalidate(),调用该函数后,会自动调用mContainer(即 ExplosionField对象)的onDraw(Canvas canvas) 方法,该方法内部     * 又调用了explosion(即 ExplosionAnimator对象)的draw方法(即 下面的方法),所以又会继续绘制。所以ExplosionAnimator的draw()和ExplosionField的onDraw     * 反复相互调用,直到动画时间终止为止。 这种相互调用方式跟scroller和computeScroll(),onDraw()之间的使用方式很像     */    public boolean draw(Canvas canvas) {    /*     * 属性动画是否结束。     */        if (!isStarted()) {            return false;        }                for (Particle particle : mParticles) {                    particle.advance((Float) getAnimatedValue());            if (particle.alpha > 0f) {                mPaint.setColor(particle.color);                mPaint.setAlpha((int) (Color.alpha(particle.color) * particle.alpha));                canvas.drawCircle(particle.cx, particle.cy, particle.radius, mPaint);//画到ExplosionField上            }        }        mContainer.invalidate();        return true;    }    /**     * 该方法是ExplosionAnimator重写过的 </br>     * {@inheritDoc}     *      */    @Override    public void start() {    //开启计时        super.start();        //开始绘制粒子        mContainer.invalidate(mBound);    }    /**     * 爆炸粒子     *     */    private class Particle {        float alpha;        int color;        float cx;//粒子当前中心x坐标        float cy;//粒子当前中心y坐标        float radius;        float baseCx;//粒子原始x坐标        float baseCy;//粒子原始y坐标        float baseRadius;//粒子原始半径        float top;        float bottom;        float mag;        float neg;        float life;        float overflow;        /**         * 计算爆炸后该粒子的圆心坐标和半径         * @param factor 因子         */        public void advance(float factor) {            float f = 0f;            float normalization = factor / END_VALUE;            if (normalization < life || normalization > 1f - overflow) {                alpha = 0f;                return;            }            normalization = (normalization - life) / (1f - life - overflow);            float f2 = normalization * END_VALUE;            if (normalization >= 0.7f) {                f = (normalization - 0.7f) / 0.3f;            }            alpha = 1f - f;            f = bottom * f2;            cx = baseCx + f;            cy = (float) (baseCy - this.neg * Math.pow(f, 2.0)) - f * mag;            radius = V + (baseRadius - V) * f2;        }    }}


/* * Copyright (C) 2015 tyrantgit * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com.example.sss;import android.content.res.Resources;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.drawable.BitmapDrawable;import android.graphics.drawable.ColorDrawable;import android.graphics.drawable.Drawable;import android.view.View;import android.widget.ImageView;public class Utils {    private Utils() {    }    private static final float DENSITY = Resources.getSystem().getDisplayMetrics().density;    private static final Canvas sCanvas = new Canvas();    public static int dp2Px(int dp) {        return Math.round(dp * DENSITY);    }    /**     * 把View画到Bitmap上返回     * @param view     * @return     */    public static Bitmap createBitmapFromView(View view) {                if (view instanceof ImageView) {        /**         * Drawable是一个描述图片样子的类,只是描述,所以颜色等也可以是一个Drawable,若是ColorDrawable则需要创建bitmap,并把颜色绘制到bitmap上,         * 下面只是简单处理了一下当时BitmapDrawable,并没有处理是ColorDrawable时。其实获取view的镜像也可以采用这种方法:         *  view.setDrawingCacheEnabled(true);Bitmap bitmap=Bitmap.createBitmap(view.getDrawingCache());view.setDrawingCacheEnabled(false);return bitmap;         *          */             Drawable drawable = ((ImageView) view).getDrawable();            if (drawable != null && drawable instanceof BitmapDrawable) {                return ((BitmapDrawable) drawable).getBitmap();            }        }        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);//手动调用view的draw将导致view被绘制到了空白的bitmap上                canvas.setBitmap(null);            }        }        return bitmap;    }    /**     * 当创建图片导致内存溢出时,并且尝试次数没达到retryCount时,回收内存,再次执行创建,     * @param width     * @param height     * @param config     * @param retryCount     * @return     */    public static Bitmap createBitmapSafely(int width, int height, Bitmap.Config config, int retryCount) {        try {        //创建指定width*height大小,并且颜色是config的空白图片            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;        }    }}

0 0
原创粉丝点击