美文网首页
android仿58跳动图形加载动画

android仿58跳动图形加载动画

作者: WhenMeet | 来源:发表于2019-03-06 17:15 被阅读2次

    想要知道关于更多自定义View的实例,请参考:android自定义View索引
    先上个效果图,以免大家跑错地了。

    image
    用高清的每次只能录三秒,不管了,大家能懂啥意思就行。
    大家看这效果就感觉比较复杂了,事实上比一般的复杂一点。
    看到这个样子的动画,首先我们需要理智分析,不要别表面现象所迷糊了,其实就是两个东西:
    一:属性
    二:动画
    详细说呢就是,一是物体颜色的变化和形状的变化,二是动画的跳动。

    属性

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

    方形 :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。

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

        @Override
        protected void onFinishInflate() {*
            super.onFinishInflate();*
            startAnimate(0);      //开始动画*
        }
    

    //界面被销毁

        @Override
        protected void onDetachedFromWindow() {
            super.onDetachedFromWindow();
            stopAnimate();     //停止动画
        }
    

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

    说到这里所有的运转流程大家应该也就比较清楚了,具体的操作大家还是要去代码里面感受一下,具体的使用大家直接使用动画控件就行,动画控件的代码是在属性代码的基础上使用的。
    先给属性的代码
    不断变换图形的加载动画,仿58,参考链接:https://github.com/zzz40500/android-shapeLoadingView
    总的来说,颜色变换的速度收两个值控制,一个是: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();
            }
        }
    

    喜欢我的文章的,请点击关注我哦。万学冬的简书

    相关文章

      网友评论

          本文标题:android仿58跳动图形加载动画

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