仿小米MIUI卸载APP的动画(NineOld实现)

来源:互联网 发布:java ee eclipse 编辑:程序博客网 时间:2024/05/16 07:28

之前用过NineOld实现几个非常简单的动画后就放在那里了,这几天又重新捡起来自己简单封装了下去研究了下(我一直觉得动画才是Android交互的第一生产力)。demo的Git地址
https://github.com/qtstsq55/SimilarMiUiUnistallAppAnimation
说是仿MIUI的卸载动画,其实还差很远,本人反复研究了它的坐标轨迹,不过本人三角函数真心一般,只能画出个大概模子。(哪位大神知道它的轨迹函数可以告诉我啊!) 简单看下效果图吧
这里写图片描述这里写图片描述这里写图片描述这里写图片描述

这里只贴下主要的代码和大概NineOld的一些东西。

package com.example.xiaomiunistallappanimation;import com.example.animation.AnimationEngine;import com.example.animation.AnimationFactory;import com.example.animation.AnimatorValue;import com.example.animation.AnimatorValueImplements;import com.nineoldandroids.animation.Animator;import com.nineoldandroids.animation.Animator.AnimatorListener;import com.nineoldandroids.animation.ValueAnimator;import com.nineoldandroids.animation.ValueAnimator.AnimatorUpdateListener;import com.example.xiaomiview.UnistallView;import android.app.Activity;import android.graphics.Bitmap;import android.graphics.Color;import android.os.Bundle;import android.view.View;import android.view.View.MeasureSpec;import android.view.View.OnClickListener;import android.view.animation.DecelerateInterpolator;import android.view.animation.LinearInterpolator;import android.widget.Button;import android.widget.ImageView;import android.widget.RelativeLayout;public class MainActivity extends Activity {    private ImageView im_unistall;//卸载的图片    private Button btn_xiaomi;//卸载按钮    private Button btn_reset;//重置按钮    private UnistallView view;//绘制卸载碎片的View    private int colors[]=new int[10];    private boolean start_0=true;    private boolean start_1=true;    private boolean start_2=true;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initViews();        initEvents();        initColors();    }    private  Bitmap convertViewToBitmap(View view){        view.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));        view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());        view.buildDrawingCache();        Bitmap bitmap = view.getDrawingCache();        return bitmap;    }    //首先是从图片里提取主要的像素,我是从两条对角线中取值。    private void initColors(){        Bitmap bitmap=convertViewToBitmap(im_unistall);        int width=im_unistall.getWidth();        int height=im_unistall.getHeight();        for(int i=0;i<colors.length/2;i++){            if(i==colors.length/2-1){                colors[i]=bitmap.getPixel((int)(width*i*0.25f-1), (int)(height*i*0.25f-1));            }else{                colors[i]=bitmap.getPixel((int)(width*i*0.25f), (int)(height*i*0.25f));            }        }        for(int i=5;i<colors.length;i++){            if(i==colors.length-1){                colors[i]=bitmap.getPixel((int)(width*(i-colors.length/2)*0.25f-1), (int)(height-height*(i-colors.length/2)*0.25f));            }else{                colors[i]=bitmap.getPixel((int)(width*(i-colors.length/2)*0.25f), (int)(height-height*(i-colors.length/2)*0.25f)-1);            }        }    }    private void initViews(){        im_unistall=(ImageView) findViewById(R.id.im_unistall);        btn_xiaomi=(Button) findViewById(R.id.btn_xiaomi);        btn_reset=(Button) findViewById(R.id.btn_reset);        view=(UnistallView) findViewById(R.id.view_add);    }    private void initEvents(){        btn_xiaomi.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View arg0) {               //这里用的是自己封装出来的接口,具体就是支持同时动画,也支持串行动画的一些东东               //a1,a2是实现最初的抖动动画               AnimatorValue a1=new AnimatorValueImplements(im_unistall, "TranslationX", 0f,6f,6f,-6f,-6f,0f);               a1.getAnimator().setRepeatCount(2);               AnimatorValue a2=new AnimatorValueImplements(im_unistall, "TranslationY", 0f,-6f,6f,6f,-6f,0f);               a2.getAnimator().setRepeatCount(2);               //a3,a4是实现接下来的缩小动画               AnimatorValue a3=new AnimatorValueImplements(im_unistall, "ScaleX", 1f,0.6f,0.2f);               AnimatorValue a4=new AnimatorValueImplements(im_unistall, "ScaleY", 1f,0.6f,0.2f);               a3.before(a2);                                       a3.getAnimator().addUpdateListener(new AnimatorUpdateListener() {                @Override                public void onAnimationUpdate(ValueAnimator arg0) {                    if(start_0){                        //开始的时候先加20个碎片                        view.startAnimation(20,colors,im_unistall.getX()+ im_unistall.getWidth()/2,im_unistall.getY()+im_unistall.getHeight()/2);                        start_0=false;                    }else if((Float)(arg0.getAnimatedValue("ScaleX"))>0.3f&&(Float)(arg0.getAnimatedValue("ScaleX"))<0.4f){                        if(start_1){                           //缩小到30%再加30个碎片                           view.addBall(30, im_unistall.getX()+im_unistall.getWidth()/2,im_unistall.getY()+im_unistall.getHeight()/2);                           start_1=false;                         }                    }else if((Float)(arg0.getAnimatedValue("ScaleX"))>0.2f&&(Float)(arg0.getAnimatedValue("ScaleX"))<0.3f){                        if(start_2){                            //缩小到20%再加40个碎片                            view.addBall(40, im_unistall.getX()+im_unistall.getWidth()/2,im_unistall.getY()+im_unistall.getHeight()/2);                            start_2=false;                        }                    }                }            });               //开始串行执行动画(a1,a2一起,a3,a4一起,a3在a2后面)               AnimationEngine engine= AnimationFactory.getInstance().createEngine();               engine.startTogetherByLink(1000,new AnimatorListener() {                @Override                public void onAnimationStart(Animator arg0) {                }                @Override                public void onAnimationRepeat(Animator arg0) {                }                @Override                public void onAnimationEnd(Animator arg0) {                    im_unistall.setVisibility(View.INVISIBLE);                }                @Override                public void onAnimationCancel(Animator arg0) {                }            },a1,a2,a3,a4);            }        });        btn_reset.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View arg0) {                //重置的一些操作                start_0=true;                start_1=true;                start_2=true;                view.clearBalls();                im_unistall.setVisibility(View.VISIBLE);                AnimatorValue a1=new AnimatorValueImplements(im_unistall, "ScaleX", 0.2f,0.6f,1f);                AnimatorValue a2=new AnimatorValueImplements(im_unistall, "ScaleY", 0.2f,0.6f,1f);                AnimationFactory.getInstance().createEngine().startTogether(1000, null, a1,a2);            }        });    }}

这是绘制碎片的View代码

package com.example.xiaomiview;import java.util.ArrayList;import android.content.Context;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.drawable.ShapeDrawable;import android.graphics.drawable.shapes.OvalShape;import android.util.AttributeSet;import android.view.View;import com.example.animation.AnimationFactory;import com.example.animation.AnimatorValue;import com.example.animation.AnimatorValueImplements;import com.nineoldandroids.animation.TypeEvaluator;import com.nineoldandroids.animation.ValueAnimator;public class UnistallView  extends View implements ValueAnimator.AnimatorUpdateListener{     private ArrayList<ShapeHolder> balls = new ArrayList<ShapeHolder>();     private ArrayList<AnimatorValue> animatorValues = new ArrayList<AnimatorValue>();     private AnimatorValue bounceAnim = null;     private BallXYHolder ballHolder = null;     private int colors[];     public UnistallView(Context context) {        super(context);     }    public UnistallView(Context context,AttributeSet set) {        super(context,set);     }     @SuppressWarnings("unchecked")    private void createAnimation() {         for(int i=0,j=0;i<balls.size();i++,j++){             float X=balls.get(i).getX();             float Y= balls.get(i).getY();             float deptX,deptY,deptAlpha;             if(i%2==0){                  deptX=-i*2;              }else{                  deptX=i*2;              }             int b=balls.size()/2;             int a=j/2+5;             deptY=Y/16;             //碎片分10个动画步骤             Object holder[]=new Object[10];             deptAlpha=255/holder.length;             //抛物线路径,大概是a*sin(ax),定义域0到5π/4和a*sin(bx),b递增,定义域0到π/2.             if(i>balls.size()/2-1){                 deptX=deptX/2;                 for(int k=0;k<holder.length;k++){                         holder[k]= new XYAHolder(X+deptX*k,(float) (Y-a*(Math.sin(b*(Math.PI/b/16*k)))*deptY),255-(k+1)*deptAlpha);                 }             }else{                 for(int k=0;k<holder.length;k++){                     if(k<holder.length-1){                         holder[k]= new XYAHolder(X+deptX*k,(float) (Y-a*(Math.sin(a*(Math.PI/a/8*k)))*deptY),255-(k+1)*deptAlpha);                     }else{                         holder[k]= new XYAHolder(X+deptX*k,(float) (Y-a*(Math.sin(a*(Math.PI/a)+Math.PI/4))*deptY),255-(k+1)*deptAlpha);                     }                 }             }             ballHolder = new BallXYHolder(balls.get(i));             bounceAnim = new AnimatorValueImplements(ballHolder, new XYEvaluator(),"XYA", holder);             animatorValues.add(bounceAnim);         }     }     public void startAnimation(int num,int colors[],float x,float y) {         this.colors=colors;         for(int i=0;i<num;i++){            double r=Math.random()-0.5;             balls.add(createBall((float)(x+r*8), (float)(y+r*8),255f));         }         createAnimation();//         for(int i=0;i<animatorValues.size();i++){//             if(i>0&&i%4==0){//               animatorValues.get(i).before(animatorValues.get(i-1));//               animatorValues.get(i).getAnimator().addUpdateListener(this);//             }//         }//         AnimatorValue[] values = new AnimatorValue[animatorValues.size()];//         animatorValues.toArray(values);         animatorValues.get(0).getAnimator().addUpdateListener(this);         AnimationFactory.getInstance().createEngine().startTogether(5000, null,animatorValues);     }     //后续增加的碎片球,抛物线方程应该和初始的碎片不一致,但是这里就将就一下吧     public void addBall(int num,float x,float y){         ArrayList<AnimatorValue> animatorValues = new ArrayList<AnimatorValue>();         for(int i=0,j=0;i<num;i++,j++){             double r=Math.random()-0.5;             ShapeHolder ball=createBall((float)(x+r*16), (float)(y+r*16),255f);             balls.add(ball);             float X=ball.getX();             float Y= ball.getY();             float deptX,deptY,deptAlpha;             if(i%2==0){                  deptX=-i*2;              }else{                  deptX=i*2;              }             int a=j/2+5;             int b=balls.size()/2;             deptY=Y/16;             Object holder[]=new Object[10];             deptAlpha=255/holder.length;             if(i>balls.size()/2-1){                 deptX=deptX/2;                 for(int k=0;k<holder.length;k++){                         holder[k]= new XYAHolder(X+deptX*k,(float) (Y-a*(Math.sin(b*(Math.PI/b/16*k)))*deptY),255-(k+1)*deptAlpha);                 }             }else{                 for(int k=0;k<holder.length;k++){                     if(k<holder.length-1){                         holder[k]= new XYAHolder(X+deptX*k,(float) (Y-a*(Math.sin(a*(Math.PI/a/8*k)))*deptY),255-(k+1)*deptAlpha);                     }else{                         holder[k]= new XYAHolder(X+deptX*k,(float) (Y-a*(Math.sin(a*(Math.PI/a)+Math.PI/4))*deptY),255-(k+1)*deptAlpha);                     }                 }             }             ballHolder = new BallXYHolder(ball);             bounceAnim = new AnimatorValueImplements(ballHolder, new XYEvaluator(),"XYA",holder);             animatorValues.add(bounceAnim);         }//         for(int i=0;i<animatorValues.size();i++){//             if(i>0&&i%4==0){//               animatorValues.get(i).before(animatorValues.get(i-1));//               animatorValues.get(i).getAnimator().addUpdateListener(this);//             }//         }//         AnimatorValue[] values = new AnimatorValue[animatorValues.size()];//         animatorValues.toArray(values);         animatorValues.get(0).getAnimator().addUpdateListener(this);         AnimationFactory.getInstance().createEngine().startTogether(5000, null,animatorValues);     }     private ShapeHolder createBall(float x, float y,float alpha) {         OvalShape circle = new OvalShape();         double random=Math.random()-0.5;          float radio=(float)(20+random*16);         circle.resize(radio,radio);         ShapeDrawable drawable = new ShapeDrawable(circle);         ShapeHolder shapeHolder = new ShapeHolder(drawable);         shapeHolder.setX(x - radio/2);         shapeHolder.setY(y - radio/2);         shapeHolder.setAlpha(alpha);         Paint paint = drawable.getPaint();          int  color_random=(int) (Math.random()*colors.length);         paint.setColor(colors[color_random]);         shapeHolder.setPaint(paint);         return shapeHolder;     }     @Override     protected void onDraw(Canvas canvas) {         for (int i = 0; i < balls.size(); ++i) {             ShapeHolder shapeHolder = balls.get(i);             canvas.save();             canvas.translate(shapeHolder.getX(), shapeHolder.getY());             shapeHolder.getShape().draw(canvas);             canvas.restore();         }     }     public void onAnimationUpdate(ValueAnimator animation) {         invalidate();     }     public void clearBalls(){         balls.clear();         animatorValues.clear();     }     //匀速插值,最后onDraw中绘制的位置和透明度就是从这里计算出来的     public class XYEvaluator implements TypeEvaluator {         public Object evaluate(float fraction, Object startValue, Object endValue) {             XYAHolder startXYA = (XYAHolder) startValue;             XYAHolder endXYA = (XYAHolder) endValue;             return new XYAHolder(startXYA.getX() + fraction * (endXYA.getX() - startXYA.getX()),                     startXYA.getY() + fraction * (endXYA.getY() - startXYA.getY()),  startXYA.getAlpha() + fraction * (endXYA.getAlpha() - startXYA.getAlpha()));         }     }     public class XYAHolder {         private float mX;         private float mY;         private float  mAlpha;         public XYAHolder(float x, float y,float alpha) {             mX = x;             mY = y;             mAlpha=alpha;         }         public float getX() {             return mX;         }         public void setX(float x) {             mX = x;         }         public float getY() {             return mY;         }         public void setY(float y) {             mY = y;         }         public float getAlpha() {             return mAlpha;         }         public void setAlpha(int alpha) {             mAlpha=alpha;         }     }     public class BallXYHolder {         private ShapeHolder mBall;         public BallXYHolder(ShapeHolder ball) {             mBall = ball;         }         public void setXYA(XYAHolder xyaHolder) {             mBall.setX(xyaHolder.getX());             mBall.setY(xyaHolder.getY());             mBall.setAlpha(xyaHolder.getAlpha());         }         public XYAHolder getXYA() {             return new XYAHolder(mBall.getX(), mBall.getY(),mBall.getAlpha());         }     }}主要的部分就是这两个,还有就是自己封装出来的一些东西,算是抛砖引玉吧。
0 1
原创粉丝点击