天天看點

圓弧的動畫效果實作

需求背景:

畫一個app占用的記憶體圖,其中有三個弧,

1、背景全部記憶體的圈圈;

2、本app占用的記憶體

3、除app外其他檔案占用的大小

進來檢視緩存圖時,環形需要動态顯示

圓弧的動畫效果實作

技術分析:

從圖上看,挺簡單的,就三條圓弧,筆寬如圖這麼大就可以了;

設定三個Paint的不同顔色;

計算所占的比例;

重點以前不懂動态顯示圓弧;

網上查閱:

主要是利用ObjectAnimator 的ofFloat效果

ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(this, "progress",progress)
//progress 的getter和setter
           

View的代碼如下:

package com.github.azhansy.timepickdemo;

import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.DecelerateInterpolator;

/**
 * Created by zhanshuyong on 2017/3/10.
 * 動态的圓環圈
 */
public class CircleProgressBar extends View {

    private RectF rectF;
    private Paint initPaint;
    private Paint backgroundPaint;
    private Paint foregroundPaint;
    private Paint middlePaint;
    private Paint ratesign;
    private int backgroundColor = Color.parseColor("#999999");
    private int middleColor = Color.parseColor("#00a8ff");
    private int foregroundColor = Color.parseColor("#3F51B5");

    /**
     * 進度條以90度角起始(12點方向)
     */
    private int startAngle = -;
    private float strokeWidth = ;
    private float background = ;
    private float progressBackground = ;
    private float progress = ;
    private float secondProgress = ;
    private int min = ;
    private int max = ;

    public CircleProgressBar(Context context) {
        this(context, null);
    }

    public CircleProgressBar(Context context, AttributeSet attrs) {
        this(context, attrs, );
    }

    public CircleProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        intView(context, attrs, defStyleAttr);
    }

    private void intView(Context context, AttributeSet attrs, int defStyleAttr) {
        rectF = new RectF();
        TypedArray typedArray = context.getTheme().obtainStyledAttributes(
                attrs,
                R.styleable.CircleProgressBar,
                , );
        try {
            strokeWidth = typedArray.getDimension(R.styleable.CircleProgressBar_progressBarThickness, strokeWidth);
            progress = typedArray.getFloat(R.styleable.CircleProgressBar_progress, progress);
            secondProgress = typedArray.getFloat(R.styleable.CircleProgressBar_secondProgress, secondProgress);
            foregroundColor = typedArray.getInt(R.styleable.CircleProgressBar_progressbarColor, foregroundColor);
            middleColor = typedArray.getInt(R.styleable.CircleProgressBar_secondProgressbarColor, middleColor);
            backgroundColor = typedArray.getInt(R.styleable.CircleProgressBar_progressBarBackgroundColor, backgroundColor);
            min = typedArray.getInt(R.styleable.CircleProgressBar_min, min);
            max = typedArray.getInt(R.styleable.CircleProgressBar_max, max);
        } finally {
            typedArray.recycle();
        }

        ratesign = new Paint(Paint.ANTI_ALIAS_FLAG);
        ratesign.setColor(ContextCompat.getColor(getContext(), R.color.progress_rate));
        ratesign.setTextSize(sp2px((float) ));

        initPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        initPaint.setColor(Color.TRANSPARENT);
        initPaint.setStyle(Paint.Style.STROKE);
        initPaint.setStrokeWidth(strokeWidth);

        backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        backgroundPaint.setColor(backgroundColor);
        backgroundPaint.setStyle(Paint.Style.STROKE);
        backgroundPaint.setStrokeWidth(strokeWidth);

        foregroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        foregroundPaint.setColor(foregroundColor);
        foregroundPaint.setStyle(Paint.Style.STROKE);
        foregroundPaint.setStrokeWidth(strokeWidth);

        middlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        middlePaint.setColor(middleColor);
        middlePaint.setStyle(Paint.Style.STROKE);
        middlePaint.setStrokeWidth(strokeWidth);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawOval(rectF, initPaint);
        float angleBack =  * progressBackground / max;
        float angleMiddle =  * secondProgress / max;
        float angleFore =  * (progress + secondProgress) / max;
        canvas.drawArc(rectF, startAngle, angleBack, false, backgroundPaint);
        canvas.drawArc(rectF, startAngle, angleFore, false, foregroundPaint);
        canvas.drawArc(rectF, startAngle, angleMiddle, false, middlePaint);

//        canvas.drawText(secondProgress + "%", rectF.centerX(), rectF.centerY(), ratesign);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
        int width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
        int min = Math.min(width, height);
        setMeasuredDimension(min, min);
        rectF.set( + strokeWidth / ,  + strokeWidth / , min - strokeWidth / , min - strokeWidth - );

    }

    private ObjectAnimator animator1, animator2;


    public void setProgress(float progress) {
        this.progress = progress;
        invalidate();
    }

    public float getSecondProgress() {
        return secondProgress;
    }

    public void setSecondProgress(float secondProgress) {
        this.secondProgress = secondProgress;
        invalidate();
    }

    public float getProgressBackground() {
        return progressBackground;
    }

    public void setProgressBackground(float progressBackground) {
        this.progressBackground = progressBackground;
        invalidate();
    }

    public float getProgress() {
        return progress;
    }

    public void setMax(int max) {
        this.max = max;
        invalidate();
    }

    public void setBackgroundProgressColor(int color) {
        this.backgroundColor = color;
        backgroundPaint.setColor(color);
        invalidate();
        requestLayout();
    }

    public void setMiddleProgessColor(int color) {
        this.middleColor = color;
        middlePaint.setColor(color);
        invalidate();
        requestLayout();
    }

    public void setForegroundProgessColor(int color) {
        this.foregroundColor = color;
        foregroundPaint.setColor(color);
        invalidate();
        requestLayout();
    }

    /**
     * Set the progress with an animation.
     * Note that the {@link ObjectAnimator} Class automatically set the progress
     * so don't call the {@link CircleProgressBar#setProgress(float)} directly within this method.
     *
     * @param progress The progress it should animate to it.
     */
    public void setProgressWithAnimation(float progress) {
        ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(this, "progress", progress);
        objectAnimator.setDuration();
        objectAnimator.setInterpolator(new DecelerateInterpolator());
        animator1 = objectAnimator;
//        objectAnimator.start();
    }

    public void setSecondProgressWithAnimation(float progress) {
        ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(this, "secondProgress", progress);
        objectAnimator.setDuration();
        objectAnimator.setInterpolator(new DecelerateInterpolator());
        animator2 = objectAnimator;
        objectAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                if (animator1 != null) {
                    animator1.start();
                }
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
//        objectAnimator.start();
    }

    public void setProgressBackgroundWithAnimation(float progress) {

        ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(this, "progressBackground", progress);
        objectAnimator.setDuration();
        objectAnimator.setInterpolator(new DecelerateInterpolator());
        objectAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                if (animator2 != null) {
                    animator2.start();
                }
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
        objectAnimator.start();
    }


    private float sp2px(Float sp) {
        float scaleDensity = getContext().getResources().getDisplayMetrics().scaledDensity;
        return sp * scaleDensity;
    }
}
           

調用方法:

CircleProgressBar circle_bar = (CircleProgressBar) findViewById(R.id.circle_bar);
        circle_bar.setProgressBackgroundWithAnimation();
        circle_bar.setSecondProgressWithAnimation();
        circle_bar.setProgressWithAnimation();