博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
android仿58跳动图形加载动画
阅读量:6325 次
发布时间:2019-06-22

本文共 10287 字,大约阅读时间需要 34 分钟。

    想要知道关于更多自定义View的实例,请参考:

先上个效果图,以免大家跑错地了。

    用高清的每次只能录三秒,不管了,大家能懂啥意思就行。

    大家看这效果就感觉比较复杂了,事实上比一般的复杂一点。

    看到这个样子的动画,首先我们需要理智分析,不要别表面现象所迷糊了,其实就是两个东西:

一:属性

二:动画

    详细说呢就是,一是物体颜色的变化和形状的变化,二是动画的跳动。

属性

    那么怎么动态修改一个物体的形状和颜色,从上面的图我们可以看出来,我们使用了三个形状,方形,三角形和圆形,给出三个绘制函数:

方形:canvas.drawPath(rectPath,paint);复制代码

三角形:canvas.drawPath(trianglePath,paint);复制代码

圆形:canvas.drawCircle(controlWidth /2,controlWidth /2,controlWidth /2,paint);复制代码

    这里的方形和三角形,我们采用的是用Path的方式进行绘制,不知道啥是Path的百度一下吧,为了缩减篇幅就不说了。

    好了,那现在我们能够随心所欲的绘制这三个图形,但是我们什么时候该绘制什么图形呢?我们可以写一个枚举类,用来储存我们的形状,然后进行切换:

//变形的集中图形列表,分别是方形,三角形,圆形

public enum ShapeKind {RECT,TRIANGLE,CIRCLE}复制代码

    枚举类,写好了,包含三个图形,现在来实现了动态切换图形的形状了,我们可以用一个变量去递增,例如,我给个变量 i 初始值为 1 , 但是每次重绘的时候添加了,如果到了100,那么就开始切换成另外一个图形,并且将 i 重置为 100, 然后又去循环,这样就能不断动态的切换形状了,至于颜色不就更简单了,每个图形给不同的画笔,不就有三种颜色了 。

    但是有时我们会发现我们的重绘速度太快了,那么我们可以用定时器减慢速度:

handler.postDelayed(new Runnable() {@Override    public void run() {Message message =new Message();message.what =1;handler.sendMessage(message);}},20);复制代码

    这样的话就会每个0.02秒进行重绘一次了,速度就在我们的掌控之中了。

    整合上面的知识,我们就能绘制出一个不断变换形状和颜色的控件了,我们起名为: TransformationLoading, 然后被下面动画的类进行使用即可。

动画

    下面看看我们的物体的运动变化,观察到了三种动作,一个上升,一个下降,还有一个旋转,并且都是同时进行的,那么这样我就必须要用到一个平时不常用到的函数了:

AnimatorSet复制代码

这个函数的作用就是用来把单独的动画集合起来的工具,简单给个例子:

ObjectAnimator objectAnimator = 

ObjectAnimator.ofFloat(transformationLoading,"translationY",0,jumpDistance);ObjectAnimator scaleIndication = ObjectAnimator.ofFloat(jumpShadow,"scaleX",0.2f,1f);downAnimator =new AnimatorSet();downAnimator.playTogether(objectAnimator, scaleIndication);downAnimator.setDuration(time);复制代码

    上面的前两行分别是位移和旋转的动画,第四行则是把两个动画集合在了一起,然后第五行是设置动画时间,基本用法就是这样。

    但是我们仔细观察上面的图形,我们发现跳动的物体下面还有一个阴影和加载中三个字,不用慌,看到这里我们想到我们现在这个控件是一个容器,那我们就继承 LinearLayout 吧,起名为 JumpLoading

    这样的话就能包含三个控件了,一个TransformationLoading,也就是我们上面属性部分创造的控件,一个阴影,其实就是一个ImageView,外加一个TextView。

    那动画我们知道怎么集合再一起了,那动画上面时候开始执行和结束呢?下面给出两个函数:

//界面被加载结束@Overrideprotected void onFinishInflate() {super.onFinishInflate();startAnimate(0);      //开始动画}//界面被销毁@Overrideprotected void onDetachedFromWindow() {super.onDetachedFromWindow();stopAnimate();     //停止动画}复制代码

两个函数属于linearLayout的生命周期里面的函数,分别是刚被绘制时和被销毁时回调的函数,再这里我们可以开始和结束动画。

说到这里所有的运转流程大家应该也就比较清楚了,具体的操作大家还是要去代码里面感受一下,具体的使用大家直接使用动画控件就行,动画控件的代码是在属性代码的基础上使用的。

先给属性的代码:

/**

* 不断变换图形的加载动画,仿58,参考链接:

* 总的来说,颜色变换的速度收两个值控制,一个是:colorChangeRate,一个是time,一个颜色变换率,一个是切换颜色的速度

*/

public class TransformationLoadingextends View {public static ShapeKindshapeKind =RECT;private float currentColorChange =0f;//当前颜色切换总值    private ArgbEvaluatormAnimPercent =new ArgbEvaluator();//用来转化两种颜色的系统工具,详情自查    private Paintpaint;private float controlWidth;//控件宽度    private Handlerhandler;/** 下面的参数可以根据实际需要进行更改* */    private int mRectColor;//方形的颜色    private int mTriangleColor;//三角形的颜色    private int mCircle;//圆形的颜色    private float colorChangeRate =0.02f;//集中图形切换时颜色的变化速度,推荐0.01-0.5,数值越小颜色变化越不突兀    private long time =10;//动画的执行速度,推荐10 - 100,数值越大,动画越慢    private boolean changeKind =false;//是否开启主动切换形状的控制器    private boolean FlashingOrNot =false;//是否开启颜色闪动    private boolean animateOrNot =true;//是否执行不断刷新    public TransformationLoading(Context context) {super(context);initData();}public TransformationLoading(Context context, AttributeSet attrs) {super(context, attrs);initData();}//初始化几个图形的颜色    private void initData() {mRectColor = Color.argb(255,114,213,114);mTriangleColor = Color.argb(255,115,153,254);mCircle = Color.argb(255,232,78,64);paint =new Paint();handler =new Handler() {@Override            public void handleMessage(Message msg) {super.handleMessage(msg);switch (msg.what) {case 1:invalidate();//重绘界面                        break;}}};}@Override    protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);controlWidth = getMeasuredWidth();}@Override    protected void onDraw(Canvas canvas) {super.onDraw(canvas);switch (shapeKind) {case RECT://绘制一个正方形                currentColorChange +=colorChangeRate;if (FlashingOrNot){int rectColor = (int)mAnimPercent.evaluate(currentColorChange,mRectColor,mTriangleColor);paint.setColor(rectColor);}else {paint.setColor(mRectColor);}if (currentColorChange >1) {if (changeKind) {shapeKind =TRIANGLE;}currentColorChange =0f;}Path rectPath =new Path();rectPath.moveTo(0,0);rectPath.lineTo(controlWidth,0);rectPath.lineTo(controlWidth,controlWidth);rectPath.lineTo(0,controlWidth);rectPath.close();canvas.drawPath(rectPath,paint);if (animateOrNot) {toRefresh();}break;case TRIANGLE://绘制一个三角形                currentColorChange +=colorChangeRate;if (FlashingOrNot){int triangleColor = (int)mAnimPercent.evaluate(currentColorChange,mTriangleColor,mCircle);paint.setColor(triangleColor);}else {paint.setColor(mTriangleColor);}if (currentColorChange >1) {if (changeKind) {shapeKind =CIRCLE;}currentColorChange =0f;}Path trianglePath =new Path();trianglePath.moveTo(0.5f *controlWidth,0);trianglePath.lineTo(controlWidth,controlWidth);trianglePath.lineTo(0,controlWidth);trianglePath.close();canvas.drawPath(trianglePath,paint);if (animateOrNot) {toRefresh();}break;case CIRCLE://绘制一个圆形                currentColorChange +=colorChangeRate;if (FlashingOrNot){int circleColor = (int)mAnimPercent.evaluate(currentColorChange,mCircle,mRectColor);paint.setColor(circleColor);}else {paint.setColor(mCircle);}if (currentColorChange >1) {if (changeKind) {shapeKind =RECT;}currentColorChange =0f;}canvas.drawCircle(controlWidth /2,controlWidth /2,controlWidth /2,paint);if (animateOrNot) {toRefresh();}break;}}//用来供主动切换形状的方法    public void changeShape() {currentColorChange =0f;//重置颜色渐变数值        changeKind =false;//关闭自动切换图形的功能        switch (shapeKind) {case RECT:shapeKind =TRIANGLE;break;case TRIANGLE:shapeKind =CIRCLE;break;case CIRCLE:shapeKind =RECT;break;}}//重新刷新界面    private void toRefresh() {handler.postDelayed(new Runnable() {@Override            public void run() {Message message =new Message();message.what =1;handler.sendMessage(message);}},time);}//变形的集中图形列表,分别是方形,三角形,圆形    public enum ShapeKind {RECT,TRIANGLE,CIRCLE    }//停止动画    public void stopAnimate() {animateOrNot =false;}//开始动画    public void startAnimate() {if (!animateOrNot) {animateOrNot =true;toRefresh();}}}复制代码

再给动画的代码:

/**

* 仿58加载动画跳动的小球,和TransformationLoading控件结合起来使用,并且要关闭TransformationLoading的主动切换形状的控制器,也就是:changeKind

*/

public class JumpLoadingextends LinearLayout {private AnimatorSetupAnimator;//上升的动画集合    private AnimatorSetdownAnimator;//下降的动画集合    private boolean move =false;//当前有没有执行动画    private Runnablerunnable;private TransformationLoadingtransformationLoading;//跳动的小球    private ImageViewjumpShadow;//下面的阴影/** 下面的参数可以根据实际需要进行更改* */    private int jumpDistance =200;//跳动的距离    private int time =500;//跳动一个周期的时间,0.5秒    private int angle =180;//跳动过程中的旋转角度    public JumpLoading(Context context) {super(context);initData(context);}public JumpLoading(Context context, AttributeSet attrs) {super(context, attrs);initData(context);}private void initData(Context context) {LayoutInflater.from(context).inflate(R.layout.jump_layout,this,true);transformationLoading = (TransformationLoading) findViewById(R.id.transformationLoading);jumpShadow = (ImageView) findViewById(R.id.jumpShadow);runnable =new Runnable() {@Override            public void run() {ViewHelper.setRotation(transformationLoading,180f);ViewHelper.setTranslationY(transformationLoading,0f);ViewHelper.setScaleX(jumpShadow,0.2f);move =true;freeFall();//先执行下降动画            }};}//下降动画    private void freeFall() {if (downAnimator ==null) {ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(transformationLoading,"translationY",0,jumpDistance);ObjectAnimator scaleIndication = ObjectAnimator.ofFloat(jumpShadow,"scaleX",0.2f,1f);downAnimator =new AnimatorSet();downAnimator.playTogether(objectAnimator, scaleIndication);downAnimator.setDuration(time);downAnimator.setInterpolator(new AccelerateInterpolator(1.2f));downAnimator.addListener(new Animator.AnimatorListener() {@Override                public void onAnimationStart(Animator animation) {}@Override                public void onAnimationEnd(Animator animation) {if (move) {transformationLoading.changeShape();rise();}}@Override                public void onAnimationCancel(Animator animation) {}@Override                public void onAnimationRepeat(Animator animation) {}});}downAnimator.start();}//上升动画    private void rise() {if (upAnimator ==null) {ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(transformationLoading,"translationY",jumpDistance,0);ObjectAnimator scaleIndication = ObjectAnimator.ofFloat(jumpShadow,"scaleX",1f,0.2f);ObjectAnimator objectAnimator1 =null;objectAnimator1 = ObjectAnimator.ofFloat(transformationLoading,"rotation",0,angle);upAnimator =new AnimatorSet();upAnimator.playTogether(objectAnimator, objectAnimator1, scaleIndication);upAnimator.setDuration(time);upAnimator.setInterpolator(new DecelerateInterpolator(1.2f));upAnimator.addListener(new Animator.AnimatorListener() {@Override                public void onAnimationStart(Animator animation) {}@Override                public void onAnimationEnd(Animator animation) {if (move) {freeFall();}}@Override                public void onAnimationCancel(Animator animation) {}@Override                public void onAnimationRepeat(Animator animation) {}});}upAnimator.start();}//开始执行动画,从runnable开始,然后rise和freeFall互调    public void startAnimate(int delay) {if (!move) {if (downAnimator !=null &&downAnimator.isRunning()) {return;}this.removeCallbacks(runnable);if (delay >0) {this.postDelayed(runnable, delay);}else {this.post(runnable);}}}//停止动画,停止所有动画和监听    public void stopAnimate() {move =false;if (upAnimator !=null) {if (upAnimator.isRunning()) {upAnimator.cancel();}upAnimator.removeAllListeners();for (Animator animator :upAnimator.getChildAnimations()) {animator.removeAllListeners();}upAnimator =null;}if (downAnimator !=null) {if (downAnimator.isRunning()) {downAnimator.cancel();}downAnimator.removeAllListeners();for (Animator animator :downAnimator.getChildAnimations()) {animator.removeAllListeners();}downAnimator =null;}this.removeCallbacks(runnable);}//界面被加载结束    @Override    protected void onFinishInflate() {super.onFinishInflate();startAnimate(0);}//界面被销毁    @Override    protected void onDetachedFromWindow() {super.onDetachedFromWindow();stopAnimate();}}复制代码

                             喜欢我的文章的,请点击关注我哦。

转载于:https://juejin.im/post/5a541dd2518825734978c524

你可能感兴趣的文章
vs2010生成Dll文件并引用dll(C#)
查看>>
藏在兰州拉面里精益管理秘诀
查看>>
How to blog on Github
查看>>
百思不得姐 one day
查看>>
19.04.16--指针笔记-参数传递
查看>>
面向对象
查看>>
POJ1860 Currency Exchange
查看>>
CNN 那么多的网络有什么区别吗?看这里了解 CNN 的发展历程
查看>>
多云中如何共享责任模式
查看>>
Adenium约旦57MW太阳能光伏项目投产
查看>>
《Servlet和JSP学习指南》一3.6 动作
查看>>
物联网市场FD-SOI制程会取代FinFET吗?
查看>>
《VMware、Citrix和Microsoft虚拟化技术详解与应用实践》一2.2 ESXi简介
查看>>
CSS3中linear-gradient实现百分比进度条
查看>>
Java设计模式精讲
查看>>
数据库索引为什么用B+树实现?
查看>>
Gensim训练维基百科语料库
查看>>
iOS 10.3应用内更换icon
查看>>
全局光照---光子映射
查看>>
支持向量机---线性支持向量机与软间隔最大化
查看>>