Android仿QQ邮箱下拉刷新动画(三个小球围绕中心转动)

来源:互联网 发布:电商软件营销方案 编辑:程序博客网 时间:2024/04/30 16:03

仿QQ邮箱下拉刷新动画(三个小球围绕中心转动)

该动画的实现主要借鉴了海龙的博客- 两个小球不停的绕中心旋转的进度条 ,在此感谢下。

1 首先上图(折腾了好久才把gif给搞了上去

这里写图片描述

2 分析

2.1 当我们看到一个动画,首先需要对动画的效果进行分析,而不是盲目的进行开发

2.2 动画的分解(先需要关注一个小球的效果,避免其他干扰)

2.2.1 平移动画:把中心点的横坐标当作坐标的原点

第一个小球的x轴变化为:-1f>0f>1f>0f>-1f;

第二个小球的x轴变化为:0f>1f>0f>-1f>0f;

第三个小球的x轴变化为:1f>0f>-1f>0f>1f;

2.2.2 缩放动画:(三种大小:minRadius,centerRadius,maxRadius)

第一个小球的缩放变化为:center>max>center>min>center;

第二个小球的缩放变化为:max>center>min>center>max;

第三个小球的缩放变化为:center>min>center>max>center;

2.2.3 重要的一点:简单理解为半径大的覆盖在半径小的上方

3 分析完毕,直接上代码

public class ThreeBallRotationProgressBar extends View {    private final static int DEFAULT_MAX_RADIUS = 16;    private final static int DEFAULT_MIN_RADIUS = 5;    private final static int DEFAULT_DISTANCE = 35;    private final static int DEFAULT_ONE_BALL_COLOR = Color            .parseColor("#40df73");    private final static int DEFAULT_TWO_BALL_COLOR = Color            .parseColor("#ffdf3e");    private final static int DEFAULT_THREE_BALL_COLOR = Color            .parseColor("#ff733e");    private final static int DEFAULT_ANIMATOR_DURATION = 1400;    private Paint mOnePaint;    private Paint mTwoPaint;    private Paint mThreePaint;    private float maxRadius = DEFAULT_MAX_RADIUS;    private float minRadius = DEFAULT_MIN_RADIUS;    private int distance = DEFAULT_DISTANCE;    private long duration = DEFAULT_ANIMATOR_DURATION;    private Ball mOneBall;    private Ball mTwoBall;    private Ball mThreeBall;    private float mCenterX;    private float mCenterY;    private AnimatorSet animatorSet;    public ThreeBallRotationProgressBar(Context context) {        this(context, null);    }    public ThreeBallRotationProgressBar(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public ThreeBallRotationProgressBar(Context context, AttributeSet attrs,            int defStyleAttr) {        super(context, attrs, defStyleAttr);        init(context);    }    private void init(Context context) {        mOneBall = new Ball();        mTwoBall = new Ball();        mThreeBall = new Ball();        mOneBall.setColor(DEFAULT_ONE_BALL_COLOR);        mTwoBall.setColor(DEFAULT_TWO_BALL_COLOR);        mThreeBall.setColor(DEFAULT_THREE_BALL_COLOR);        mOnePaint = new Paint(Paint.ANTI_ALIAS_FLAG);        mOnePaint.setColor(DEFAULT_ONE_BALL_COLOR);        mTwoPaint = new Paint(Paint.ANTI_ALIAS_FLAG);        mTwoPaint.setColor(DEFAULT_TWO_BALL_COLOR);        mThreePaint = new Paint(Paint.ANTI_ALIAS_FLAG);        mThreePaint.setColor(DEFAULT_THREE_BALL_COLOR);        configAnimator();    }    @Override    protected void onSizeChanged(int w, int h, int oldw, int oldh) {        super.onSizeChanged(w, h, oldw, oldh);        mCenterX = w / 2;        mCenterY = h / 2;    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        mCenterX = getWidth() / 2;        mCenterY = getHeight() / 2;    }    @Override    protected void onDraw(Canvas canvas) {        if (mOneBall.getRadius() >= mTwoBall.getRadius()) {            if (mThreeBall.getRadius() >= mOneBall.getRadius()) {                canvas.drawCircle(mTwoBall.getCenterX(), mCenterY,                        mTwoBall.getRadius(), mTwoPaint);                canvas.drawCircle(mOneBall.getCenterX(), mCenterY,                        mOneBall.getRadius(), mOnePaint);                canvas.drawCircle(mThreeBall.getCenterX(), mCenterY,                        mThreeBall.getRadius(), mThreePaint);            } else {                if (mTwoBall.getRadius() <= mThreeBall.getRadius()) {                    canvas.drawCircle(mTwoBall.getCenterX(), mCenterY,                            mTwoBall.getRadius(), mTwoPaint);                    canvas.drawCircle(mThreeBall.getCenterX(), mCenterY,                            mThreeBall.getRadius(), mThreePaint);                    canvas.drawCircle(mOneBall.getCenterX(), mCenterY,                            mOneBall.getRadius(), mOnePaint);                } else {                    canvas.drawCircle(mThreeBall.getCenterX(), mCenterY,                            mThreeBall.getRadius(), mThreePaint);                    canvas.drawCircle(mTwoBall.getCenterX(), mCenterY,                            mTwoBall.getRadius(), mTwoPaint);                    canvas.drawCircle(mOneBall.getCenterX(), mCenterY,                            mOneBall.getRadius(), mOnePaint);                }            }        } else {            if (mThreeBall.getRadius() >= mTwoBall.getRadius()) {                canvas.drawCircle(mOneBall.getCenterX(), mCenterY,                        mOneBall.getRadius(), mOnePaint);                canvas.drawCircle(mTwoBall.getCenterX(), mCenterY,                        mTwoBall.getRadius(), mTwoPaint);                canvas.drawCircle(mThreeBall.getCenterX(), mCenterY,                        mThreeBall.getRadius(), mThreePaint);            } else {                if (mOneBall.getRadius() <= mThreeBall.getRadius()) {                    canvas.drawCircle(mOneBall.getCenterX(), mCenterY,                            mOneBall.getRadius(), mOnePaint);                    canvas.drawCircle(mThreeBall.getCenterX(), mCenterY,                            mThreeBall.getRadius(), mThreePaint);                    canvas.drawCircle(mTwoBall.getCenterX(), mCenterY,                            mTwoBall.getRadius(), mTwoPaint);                } else {                    canvas.drawCircle(mThreeBall.getCenterX(), mCenterY,                            mThreeBall.getRadius(), mThreePaint);                    canvas.drawCircle(mOneBall.getCenterX(), mCenterY,                            mOneBall.getRadius(), mOnePaint);                    canvas.drawCircle(mTwoBall.getCenterX(), mCenterY,                            mTwoBall.getRadius(), mTwoPaint);                }            }        }    }    private void configAnimator() {        float centerRadius = (maxRadius + minRadius) * 0.5f;        ObjectAnimator oneScaleAnimator = ObjectAnimator.ofFloat(mOneBall,                "radius", centerRadius, maxRadius, centerRadius, minRadius,                centerRadius);        oneScaleAnimator.setRepeatCount(ValueAnimator.INFINITE);        ValueAnimator oneCenterAnimator = ValueAnimator                .ofFloat(-1, 0, 1, 0, -1);        oneCenterAnimator.setRepeatCount(ValueAnimator.INFINITE);        oneCenterAnimator                .addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {                    @Override                    public void onAnimationUpdate(ValueAnimator animation) {                        float value = (Float) animation.getAnimatedValue();                        float x = mCenterX + (distance) * value;                        mOneBall.setCenterX(x);                        invalidate();                    }                });        ValueAnimator oneAlphaAnimator = ValueAnimator.ofFloat(0.8f, 1, 0.8f,                0, 0.8f);        oneAlphaAnimator.setRepeatCount(ValueAnimator.INFINITE);        oneAlphaAnimator                .addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {                    @Override                    public void onAnimationUpdate(ValueAnimator animation) {                        float value = (Float) animation.getAnimatedValue();                        int alpha = (int) (255 * value);                        mOnePaint.setAlpha(alpha);                    }                });        ObjectAnimator twoScaleAnimator = ObjectAnimator.ofFloat(mTwoBall,                "radius", maxRadius, centerRadius, minRadius, centerRadius,                maxRadius);        twoScaleAnimator.setRepeatCount(ValueAnimator.INFINITE);        ValueAnimator twoCenterAnimator = ValueAnimator.ofFloat(0, 1, 0, -1, 0);        twoCenterAnimator.setRepeatCount(ValueAnimator.INFINITE);        twoCenterAnimator                .addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {                    @Override                    public void onAnimationUpdate(ValueAnimator animation) {                        float value = (Float) animation.getAnimatedValue();                        float x = mCenterX + (distance) * value;                        mTwoBall.setCenterX(x);                    }                });        ValueAnimator twoAlphaAnimator = ValueAnimator.ofFloat(1, 0.8f, 0,                0.8f, 1);        twoAlphaAnimator.setRepeatCount(ValueAnimator.INFINITE);        twoAlphaAnimator                .addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {                    @Override                    public void onAnimationUpdate(ValueAnimator animation) {                        float value = (Float) animation.getAnimatedValue();                        int alpha = (int) (255 * value);                        mTwoPaint.setAlpha(alpha);                    }                });        ObjectAnimator threeScaleAnimator = ObjectAnimator.ofFloat(mThreeBall,                "radius", centerRadius, minRadius, centerRadius, maxRadius,                centerRadius);        threeScaleAnimator.setRepeatCount(ValueAnimator.INFINITE);        ValueAnimator threeCenterAnimator = ValueAnimator.ofFloat(1, 0, -1, 0,                1);        threeCenterAnimator.setRepeatCount(ValueAnimator.INFINITE);        threeCenterAnimator                .addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {                    @Override                    public void onAnimationUpdate(ValueAnimator animation) {                        float value = (Float) animation.getAnimatedValue();                        float x = mCenterX + (distance) * value;                        mThreeBall.setCenterX(x);                    }                });        ValueAnimator threeAlphaAnimator = ValueAnimator.ofFloat(0.8f, 0, 0.8f,                1, 0.8f);        threeAlphaAnimator.setRepeatCount(ValueAnimator.INFINITE);        threeAlphaAnimator                .addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {                    @Override                    public void onAnimationUpdate(ValueAnimator animation) {                        float value = (Float) animation.getAnimatedValue();                        int alpha = (int) (255 * value);                        mThreePaint.setAlpha(alpha);                    }                });        animatorSet = new AnimatorSet();        animatorSet.playTogether(oneScaleAnimator, oneCenterAnimator,                twoScaleAnimator, twoCenterAnimator, threeScaleAnimator,                threeCenterAnimator);        animatorSet.setDuration(DEFAULT_ANIMATOR_DURATION);        animatorSet.setInterpolator(new LinearInterpolator());    }    public class Ball {        private float radius;        private float centerX;        private int color;        public float getRadius() {            return radius;        }        public void setRadius(float radius) {            this.radius = radius;        }        public float getCenterX() {            return centerX;        }        public void setCenterX(float centerX) {            this.centerX = centerX;        }        public int getColor() {            return color;        }        public void setColor(int color) {            this.color = color;        }    }    @Override    public void setVisibility(int v) {        if (getVisibility() != v) {            super.setVisibility(v);            if (v == GONE || v == INVISIBLE) {                stopAnimator();            } else {                startAnimator();            }        }    }    @Override    protected void onVisibilityChanged(View changedView, int v) {        super.onVisibilityChanged(changedView, v);        if (v == GONE || v == INVISIBLE) {            stopAnimator();        } else {            startAnimator();        }    }    @Override    protected void onAttachedToWindow() {        super.onAttachedToWindow();        startAnimator();    }    @Override    protected void onDetachedFromWindow() {        super.onDetachedFromWindow();        stopAnimator();    }    public void setOneBallColor(int color) {        mOneBall.setColor(color);    }    public void setmTwoBallColor(int color) {        mTwoBall.setColor(color);    }    public void setMaxRadius(float maxRadius) {        this.maxRadius = maxRadius;        configAnimator();    }    public void setMinRadius(float minRadius) {        this.minRadius = minRadius;        configAnimator();    }    public void setDistance(int distance) {        this.distance = distance;    }    public void setDuration(long duration) {        this.duration = duration;        if (animatorSet != null) {            animatorSet.setDuration(duration);        }    }    public void startAnimator() {        if (getVisibility() != VISIBLE)            return;        if (animatorSet.isRunning())            return;        if (animatorSet != null) {            animatorSet.start();        }    }    public void stopAnimator() {        if (animatorSet != null) {            animatorSet.end();        }    }}

3.1 configAnimator()方法主要就是实现2中分析的动画效果

3.2 为了解决2中提到的重要一点,半径大的小球覆盖在半径小的小球上方,主要在onDraw()采用比较的方式实现

4 总结

4.1 掌阅iReader的下拉刷新也采用了类似的动画效果(三个方形围绕中心转动),大家可以参考本文章,试着实现里边的动画效果。相信自己写过,总能有不少收获的~

4.2 对于android动画,还是需要耐心的分析,当然熟悉的掌握动画实现还是必要的!

5 源码下载

下载地址

0 0