美文网首页
简单的自定义进度view

简单的自定义进度view

作者: RoyAlex | 来源:发表于2018-10-25 15:55 被阅读7次

首先附上效果图

device-2018-10-25-154636.2018-10-25 15_52_26.gif
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.CornerPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.support.annotation.IntDef;
import android.support.annotation.Nullable;
import android.support.annotation.Size;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.LinearInterpolator;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

//进度view用动画来表达进度:成功、失败、进行中、倒计
public class ProgressView extends View {
    //颜色
    private int progressed_color, unProgressed_color, success_color, failure_color, solidColor;
    //尺寸
    private int circle_radius = 50, circle_thickness, result_thickness;
    //默认颜色
    private static int DEFAULT_COLOR = Color.WHITE;
    //数据
    private int currentProgress, totalProgress = 100;
    //状态 0 processing 1 success 2 failure
    @Size(min = 0, max = 360)
    private int arcAngle = 40;
    @PV_STATUS
    private int status = PV_STATUS.success;

    private RectF rectF;
    //画笔
    private Paint mProgressPaint, mSuccessPaint, mFailurePaint, mSolidPaint;


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

    public ProgressView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ProgressView);
        progressed_color = array.getColor(R.styleable.ProgressView_progressedColor, Color.GREEN);
        unProgressed_color = array.getColor(R.styleable.ProgressView_unProgressedColor, DEFAULT_COLOR);
        success_color = array.getColor(R.styleable.ProgressView_successColor, Color.WHITE);
        failure_color = array.getColor(R.styleable.ProgressView_failureColor, Color.RED);
        circle_radius = array.getDimensionPixelOffset((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX,
                R.styleable.ProgressView_radius, context.getResources().getDisplayMetrics()), 50);
        circle_thickness = array.getDimensionPixelOffset((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX,
                R.styleable.ProgressView_thickness, context.getResources().getDisplayMetrics()), 22);
        result_thickness = array.getDimensionPixelOffset((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX,
                R.styleable.ProgressView_statusThickness, context.getResources().getDisplayMetrics()), 18);
        solidColor = array.getColor(R.styleable.ProgressView_fillColor, Color.GREEN);
        totalProgress = array.getInteger(R.styleable.ProgressView_totalProgress, 100);
        array.recycle();
        init();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(2*circle_radius + circle_thickness, 2*circle_radius + circle_thickness);
    }

    //初始化各项操作
    private void init() {
        mProgressPaint = new Paint();
        mSuccessPaint = new Paint();
        mFailurePaint = new Paint();
        mSolidPaint = new Paint();

        mSolidPaint.setColor(solidColor);
        mSolidPaint.setAntiAlias(true);
        mSolidPaint.setDither(true);
        mSolidPaint.setStyle(Paint.Style.FILL);


        mProgressPaint.setStrokeWidth(circle_thickness);
        mProgressPaint.setAntiAlias(true);
        mProgressPaint.setDither(true);
        mProgressPaint.setStyle(Paint.Style.STROKE);
        mProgressPaint.setStrokeCap(Paint.Cap.ROUND);
        mProgressPaint.setColor(progressed_color);

        mSuccessPaint.setAntiAlias(true);
        mSuccessPaint.setStrokeCap(Paint.Cap.ROUND);
        mSuccessPaint.setDither(true);
        mSuccessPaint.setColor(success_color);
        mSuccessPaint.setStrokeWidth(result_thickness);
        mSuccessPaint.setStyle(Paint.Style.STROKE);
        mSuccessPaint.setPathEffect(new CornerPathEffect(45));

        mFailurePaint.setColor(failure_color);
        mFailurePaint.setStyle(Paint.Style.STROKE);
        mFailurePaint.setStrokeWidth(result_thickness);
        mFailurePaint.setAntiAlias(true);
        mFailurePaint.setStrokeCap(Paint.Cap.ROUND);
        mFailurePaint.setDither(true);
        mFailurePaint.setStrokeWidth(result_thickness);
        rectF = new RectF(circle_thickness/2, circle_thickness/2, circle_radius * 2 + circle_thickness/2,
                circle_radius * 2 + circle_thickness/2);
        successPath = new Path();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawCircle(circle_radius + circle_thickness/2, circle_radius + circle_thickness/2,
                circle_radius - circle_thickness/2, mSolidPaint);
        switch (status) {
            default:
                break;
            case PV_STATUS.failure:
                canvas.drawArc(rectF, -51.4f, failAngel
                        , false, mProgressPaint);
                canvas.drawLine(0.4f * (circle_radius + circle_thickness/2),0.2f* (circle_radius + circle_thickness/2),
                        xLeft, 4f/3* xLeft -1f/3* (circle_radius + circle_thickness/2),mFailurePaint);
                canvas.drawLine(0.4f * (circle_radius + circle_thickness/2),1.8f* (circle_radius + circle_thickness/2),
                        xLeft, 7f/3*(circle_radius + circle_thickness/2) - 4f/3* xLeft,mFailurePaint);
                break;
            case PV_STATUS.process:
                float startAngle = (currentProgress * 360) / totalProgress;
                canvas.drawArc(rectF, startAngle, startAngle + arcAngle
                        , false, mProgressPaint);
                break;
            case PV_STATUS.success:
                canvas.drawArc(rectF, 180, successAngel
                        , false, mProgressPaint);
                canvas.drawPath(successPath, mSuccessPaint);
                break;
        }

    }

    public void setStatus(@PV_STATUS int status) {
        this.status = status;
        switch (status) {
            default:
                break;
            case PV_STATUS.failure:
                mProgressPaint.setColor(Color.RED);
                mFailurePaint.setColor(Color.WHITE);
                mSolidPaint.setColor(Color.RED);
                if(failureSet != null && failureSet.isRunning()){
                    failureSet.cancel();
                }
                startFailureAnimation();
                break;
            case PV_STATUS.process:
                mSolidPaint.setColor(Color.GREEN);
                mProgressPaint.setColor(Color.GREEN);
                if (processAnimator != null && processAnimator.isRunning()) {
                    processAnimator.cancel();
                }
                startProcessAnimation();
                break;
            case PV_STATUS.success:
                mProgressPaint.setColor(Color.GREEN);
                mFailurePaint.setColor(Color.WHITE);
                mSolidPaint.setColor(Color.GREEN);
                if (successSet != null && successSet.isRunning()) {
                    successSet.cancel();
                }
                successPath.rewind();
                successPath.moveTo(0, circle_radius);
                startSuccessAnimation();
                break;
        }
    }

    ValueAnimator processAnimator;
    AnimatorSet successSet;

    private void startProcessAnimation() {
        processAnimator = ValueAnimator.ofInt(0, totalProgress);
        processAnimator.setInterpolator(new LinearInterpolator());
        processAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                currentProgress = (int) valueAnimator.getAnimatedValue();
                invalidate();
            }
        });
        processAnimator.setDuration(2000);
        processAnimator.setRepeatCount(ValueAnimator.INFINITE);
        processAnimator.setRepeatMode(ValueAnimator.REVERSE);
        processAnimator.start();
    }

    private Path successPath;
    private int successAngel = 0,failAngel = 0;

    private void startSuccessAnimation() {
        successSet = new AnimatorSet();
        ValueAnimator process = ValueAnimator.ofInt(0,360);
        ValueAnimator suXPathAnimator = ValueAnimator.ofFloat(0f + circle_thickness/2, 0.8f * (circle_radius+circle_thickness/2), 1.8f * (circle_radius+circle_thickness/2));
        ValueAnimator suYPathAnimator = ValueAnimator.ofFloat(circle_radius + circle_thickness/2, 1.6f * (circle_radius+circle_thickness/2), 0.4f * (circle_radius+circle_thickness/2));
        suYPathAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                successPath.lineTo((float) suXPathAnimator.getAnimatedValue(),
                        (float) suYPathAnimator.getAnimatedValue());
                invalidate();
            }
        });
        process.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                successAngel = (int) valueAnimator.getAnimatedValue();
            }
        });
        successSet.setDuration(1000);
        successSet.setInterpolator(new AccelerateDecelerateInterpolator());
        successSet.play(suXPathAnimator)
                .with(suYPathAnimator)
                .with(process);
        successSet.start();
    }

    private AnimatorSet failureSet;
    private float xLeft =0;
    private void startFailureAnimation() {
        failureSet = new AnimatorSet();
        ValueAnimator failureAnim = ValueAnimator.ofFloat(0.4f* (circle_radius
               + circle_thickness/2),1.6f* (circle_radius +circle_thickness/2));
        failureAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                xLeft = (float) valueAnimator.getAnimatedValue();
                invalidate();
            }
        });
        ValueAnimator process = ValueAnimator.ofInt(0,360);
        process.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                failAngel = (int) valueAnimator.getAnimatedValue();
            }
        });

        failureSet.play(failureAnim)
                .with(process);
        failureSet.setDuration(1000);
        failureSet.setInterpolator(new AccelerateDecelerateInterpolator());
        failureSet.start();
    }

    @IntDef({PV_STATUS.process, PV_STATUS.success, PV_STATUS.failure})
    @Retention(RetentionPolicy.SOURCE)
    public @interface PV_STATUS {
        int process = 0;
        int success = 1;
        int failure = 2;
    }

}

附上

相关文章

网友评论

      本文标题:简单的自定义进度view

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