仿小米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
- 仿小米MIUI卸载APP的动画(NineOld实现)
- 仿MIUI的Toast动画效果实现
- 仿MIUI toast 动画效果实现
- 仿MIUI日出日落动画实现
- 网上某位大神写的仿小米卸载动画eclipse版
- 仿小米通讯录 右侧滑动条与带动画的悬停列表实现(一)
- 仿小米通讯录 右侧滑动条与带动画的悬停列表实现(二)
- 仿小米卸载程序时图标的爆炸效果
- Android特效专辑(五)——自定义圆形头像和仿MIUI卸载动画—粒子爆炸
- Android特效专辑(五)——自定义圆形头像和仿MIUI卸载动画—粒子爆炸
- adnroid仿miui的dialog
- adnroid仿miui的dialog
- 整理仿小米卸载动画打包成jar包直接使用(转载)
- 计算器,单位换算源码,仿小米APP,非常简单的
- 仿MIUI音量变化环形进度条实现
- 仿自下向上动画弹出菜单(同时背景窗口变暗/缩小)的实现原理,例小米,苹果等菜单
- 解决小米miui系统调用系统裁剪图片功能camera.action.CROP后崩溃或重新打开app的问题
- 解决小米miui系统调用系统裁剪图片功能camera.action.CROP后崩溃或重新打开app的问题
- nagios插件之监控多个tomcat线程数
- LeetCode 215:Kth Largest Element in an Array
- OpenWRT 路由配置技巧
- Android学习之 Scroller的介绍与使用
- Golang学习笔记--log包
- 仿小米MIUI卸载APP的动画(NineOld实现)
- C++异常(1) - 异常介绍
- 计算机网络各层协议
- Hadoop之——有趣问答(一)
- 如何在TableViewController中得到触摸点坐标
- What is Android?
- 快速排序法
- [LeetCode]Add Two Numbers
- 基于imgAreaSelect的用户图像截取