Customize the view to draw a circle dynamically

Custom dynamic view to draw a circle

1. CircleBarView class

public class CircleBarView extends View {
    private Paint bgPaint;//绘制背景圆弧的画笔
    private Paint progressPaint;//绘制圆弧的画笔
    private RectF mRectF;//绘制圆弧的矩形区域
    private CircleBarAnim anim;
    private int progressNum;//可以更新的进度条数值
    private float maxNum;//进度条最大值
    private int progressColor;//进度条圆弧颜色
    private int bgColor;//背景圆弧颜色
    private float startAngle;//背景圆弧的起始角度
    private float sweepAngle;//背景圆弧扫过的角度
    private float barWidth;//圆弧进度条宽度
    private int defaultSize;//自定义View默认的宽高
    private float progressSweepAngle;//进度条圆弧扫过的角度
    private TextView textView;
    private OnAnimationListener onAnimationListener;
    private Context contexts;

    public CircleBarView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        contexts = context;
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleBarView);
        progressColor = typedArray.getColor(R.styleable.CircleBarView_progress_color, Color.GREEN);
        bgColor = typedArray.getColor(R.styleable.CircleBarView_bg_color, Color.GRAY);
        startAngle = typedArray.getFloat(R.styleable.CircleBarView_start_angle, 0);
        sweepAngle = typedArray.getFloat(R.styleable.CircleBarView_sweep_angle, 360);
        barWidth = typedArray.getDimension(R.styleable.CircleBarView_bar_width, DpOrPxUtils.dip2px(context, 10));
        typedArray.recycle();//typedArray用完之后需要回收,防止内存泄漏

        progressNum = 0;
        maxNum = 100;
        defaultSize = DpOrPxUtils.dip2px(context, 100);
        mRectF = new RectF();
        anim = new CircleBarAnim();

        progressPaint = new Paint();
        progressPaint.setStyle(Paint.Style.STROKE);//只描边,不填充
        progressPaint.setColor(progressColor);
        progressPaint.setAntiAlias(true);//设置抗锯齿
        progressPaint.setStrokeWidth(barWidth);
//        progressPaint.setStrokeCap(Paint.Cap.ROUND);//设置画笔为圆角

        bgPaint = new Paint();
        bgPaint.setStyle(Paint.Style.STROKE);//只描边,不填充
        bgPaint.setColor(bgColor);
        bgPaint.setAntiAlias(true);//设置抗锯齿
        bgPaint.setStrokeWidth(barWidth);
        bgPaint.setStrokeCap(Paint.Cap.ROUND);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int height = measureSize(defaultSize, heightMeasureSpec);
        int width = measureSize(defaultSize, widthMeasureSpec);
        int min = Math.min(width, height);// 获取View最短边的长度
        setMeasuredDimension(min, min);// 强制改View为以最短边为长度的正方形
        if (min >= barWidth * 2) {
            mRectF.set(barWidth / 2, barWidth / 2, min - barWidth / 2, min - barWidth / 2);
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawArc(mRectF, startAngle, sweepAngle, false, bgPaint);
        canvas.drawArc(mRectF, startAngle, progressSweepAngle, false, progressPaint);
    }

    public class CircleBarAnim extends Animation {
        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            super.applyTransformation(interpolatedTime, t);
            progressSweepAngle = interpolatedTime * sweepAngle * progressNum / maxNum;
            if (textView != null) {
                textView.setText(onAnimationListener.howToChangeText((int) interpolatedTime, progressNum, maxNum));
                if (textView.getText().toString().equals("100%")) {                   
                    textView.setText(contexts.getString(R.string.vpn_connected));
                } else {
                    textView.setText(contexts.getString(R.string.vpn_linking) + "...");

                }
            }
            onAnimationListener.howTiChangeProgressColor(progressPaint, interpolatedTime, progressNum, maxNum);
            postInvalidate();
        }
    }

    private int measureSize(int defaultSize, int measureSpec) {
        int result = defaultSize;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        } else if (specMode == MeasureSpec.AT_MOST) {
            result = Math.min(result, specSize);
        }
        return result;
    }

    /**
     * 设置进度条最大值
     *
     * @param maxNum
     */
    public void setMaxNum(float maxNum) {
        this.maxNum = maxNum;
    }

    /**
     * 设置进度条数值
     *
     * @param progressNum 进度条数值
     * @param time        动画持续时间
     */
    public void setProgressNum(int progressNum, int time) {
        this.progressNum = progressNum;
        anim.setDuration(time);
        this.startAnimation(anim);
    }

    /**
     * 设置显示文字的TextView
     *
     * @param textView
     */
    public void setTextView(TextView textView) {
        this.textView = textView;
    }

    public interface OnAnimationListener {
        /**
         * 如何处理要显示的文字内容
         *
         * @param interpolatedTime 从0渐变成1,到1时结束动画
         * @param updateNum        进度条数值
         * @param maxNum           进度条最大值
         * @return
         */
        String howToChangeText(int interpolatedTime, float updateNum, float maxNum);

        /**
         * 如何处理进度条的颜色
         *
         * @param paint            进度条画笔
         * @param interpolatedTime 从0渐变成1,到1时结束动画
         * @param updateNum        进度条数值
         * @param maxNum           进度条最大值
         */
        void howTiChangeProgressColor(Paint paint, float interpolatedTime, float updateNum, float maxNum);
    }

    public void setOnAnimationListener(OnAnimationListener onAnimationListener) {
        this.onAnimationListener = onAnimationListener;
    }

}

2. DpOrPxUtils class

public class DpOrPxUtils {
    public static int dip2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }
}

3. LinearGradientUtil class

public class LinearGradientUtil {
    private int mStartColor;
    private int mEndColor;

    public LinearGradientUtil(int startColor, int endColor) {
        this.mStartColor = startColor;
        this.mEndColor = endColor;
    }

    //获取某一个百分比间的颜色,radio取值[0,1]
    public int getColor(float radio) {
        int redStart = Color.red(mStartColor);
        int blueStart = Color.blue(mStartColor);
        int greenStart = Color.green(mStartColor);
        int redEnd = Color.red(mEndColor);
        int blueEnd = Color.blue(mEndColor);
        int greenEnd = Color.green(mEndColor);

        int red = (int) (redStart + ((redEnd - redStart) * radio + 0.5));
        int greed = (int) (greenStart + ((greenEnd - greenStart) * radio + 0.5));
        int blue = (int) (blueStart + ((blueEnd - blueStart) * radio + 0.5));
        return Color.argb(255, red, greed, blue);
    }
}

4、activity

//文字导入
        circle_view.setTextView(tv_connecting)

        circle_view.setOnAnimationListener(object : CircleBarView.OnAnimationListener {
            override fun howToChangeText(
                interpolatedTime: Int,
                updateNum: Float,
                maxNum: Float,
            ): String? {
                val decimalFormat = DecimalFormat("0")
                return decimalFormat.format((interpolatedTime * updateNum / maxNum * 100).toDouble()) + "%"
            }

            override fun howTiChangeProgressColor(
                paint: Paint,
                interpolatedTime: Float,
                updateNum: Float,
                maxNum: Float,
            ) {
                val linearGradientUtil = LinearGradientUtil(Color.BLUE, Color.BLUE)
                paint.color = linearGradientUtil.getColor(interpolatedTime)
            }
        })

        circle_view.setProgressNum(100, 2000)

5. java code

//id
        circleBarView.setTextView(textProgress);
        circleBarView.setOnAnimationListener(new CircleBarView.OnAnimationListener() {
            @Override
            public String howToChangeText(int interpolatedTime, float updateNum, float maxNum) {
                DecimalFormat decimalFormat = new DecimalFormat("0");
                String s = decimalFormat.format(interpolatedTime * updateNum / maxNum * 100) + "%";
                return s;
            }

            @Override
            public void howTiChangeProgressColor(Paint paint, float interpolatedTime, float updateNum, float maxNum) {
                LinearGradientUtil linearGradientUtil = new LinearGradientUtil(Color.YELLOW, Color.RED);
                paint.setColor(linearGradientUtil.getColor(interpolatedTime));
            }
        });
        circleBarView.setProgressNum(100, 1000);

6. xml code

<com.example.accelerate.util.CircleBarView
            android:id="@+id/circle_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_centerInParent="true"
            android:layout_gravity="center_horizontal"
            app:bar_width="20dp"//轮廓的粗细
            app:bg_color="#DEE5FF"
            app:progress_color="#ffffff"
            app:start_angle="272"//从什么地方开始画 />  

//Picture above

Insert image description here

//Just use it directly

Guess you like

Origin blog.csdn.net/jiayuanwai/article/details/130625232