安卓自定义圆形带百分比进度条组件

java 复制代码
public class CirclePercentBar extends View {

    private Context mContext;

    private int mArcColor;
    private int mArcWidth;
    private int mCenterTextColor;
    private int mCenterTextSize;
    private int mCircleRadius;
    private Paint arcPaint;
    private Paint arcCirclePaint;
    private Paint centerTextPaint;
    private RectF arcRectF;
    private Rect textBoundRect;
    private float mCurData = 0;
    private String mSuffix = "%";
    private int arcStartColor;
    private int arcEndColor;
    private Paint startCirclePaint;

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

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

    public CirclePercentBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext = context;
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CirclePercentBar, defStyleAttr, 0);
        mArcColor = typedArray.getColor(R.styleable.CirclePercentBar_arcColor, 0xff0000);
        mArcWidth = typedArray.getDimensionPixelSize(R.styleable.CirclePercentBar_arcWidth, DisplayUtil.dp2px(context, 20));
        mCenterTextColor = typedArray.getColor(R.styleable.CirclePercentBar_centerTextColor, 0x0000ff);
        mCenterTextSize = typedArray.getDimensionPixelSize(R.styleable.CirclePercentBar_centerTextSize, DisplayUtil.dp2px(context, 20));
        mCircleRadius = typedArray.getDimensionPixelSize(R.styleable.CirclePercentBar_circleRadius, DisplayUtil.dp2px(context, 100));
        arcStartColor = typedArray.getColor(R.styleable.CirclePercentBar_arcStartColor,
                ContextCompat.getColor(mContext, R.color.colorStart));
        arcEndColor = typedArray.getColor(R.styleable.CirclePercentBar_arcEndColor,
                ContextCompat.getColor(mContext, R.color.colorEnd));

        typedArray.recycle();

        initPaint();

    }

    private void initPaint() {

        startCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        startCirclePaint.setStyle(Paint.Style.FILL);
        startCirclePaint.setColor(arcStartColor);

        arcCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        arcCirclePaint.setStyle(Paint.Style.STROKE);
        arcCirclePaint.setStrokeWidth(mArcWidth);
        arcCirclePaint.setColor(ContextCompat.getColor(mContext, R.color.colorCirclebg));
        arcCirclePaint.setStrokeCap(Paint.Cap.ROUND);

        arcPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        arcPaint.setStyle(Paint.Style.STROKE);
        arcPaint.setStrokeWidth(mArcWidth);
        arcPaint.setColor(mArcColor);
        arcPaint.setStrokeCap(Paint.Cap.ROUND);

        centerTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        centerTextPaint.setStyle(Paint.Style.FILL);
        centerTextPaint.setColor(Color.BLACK);
        centerTextPaint.setTextSize(mCenterTextSize);

        //圓弧的外接矩形
        arcRectF = new RectF();

        //文字的边界矩形
        textBoundRect = new Rect();

    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(measureDimension(widthMeasureSpec), measureDimension(heightMeasureSpec));
    }

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

    @Override
    protected void onDraw(Canvas canvas) {

        canvas.rotate(-90, getWidth() / 2, getHeight() / 2);

        arcRectF.set(getWidth() / 2 - mCircleRadius + mArcWidth / 2, getHeight() / 2 - mCircleRadius + mArcWidth / 2
                , getWidth() / 2 + mCircleRadius - mArcWidth / 2, getHeight() / 2 + mCircleRadius - mArcWidth / 2);

        canvas.drawArc(arcRectF, 0, 360, false, arcCirclePaint);

        arcPaint.setShader(new SweepGradient(getWidth() / 2, getHeight() / 2, arcStartColor, arcEndColor));
        canvas.drawArc(arcRectF, 0, 360 * mCurData / 100, false, arcPaint);

        canvas.rotate(90, getWidth() / 2, getHeight() / 2);
        canvas.drawCircle(getWidth() / 2, getHeight() / 2 - mCircleRadius + mArcWidth / 2, mArcWidth / 2, startCirclePaint);

        String data = String.valueOf((int) mCurData) + mSuffix;
        centerTextPaint.getTextBounds(data, 0, data.length(), textBoundRect);
        canvas.drawText(data, getWidth() / 2 - textBoundRect.width() / 2, getHeight() / 2 + textBoundRect.height() / 2, centerTextPaint);

    }

    public void setPercentData(float data, final String suffix, TimeInterpolator interpolator) {
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(mCurData, data);
        valueAnimator.setDuration((long) (Math.abs(mCurData - data) * 30));
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                float value = (float) valueAnimator.getAnimatedValue();
                mCurData = (float) (Math.round(value * 10)) / 10;
                mSuffix = suffix;
                invalidate();
            }
        });
        valueAnimator.setInterpolator(interpolator);
        valueAnimator.start();
    }
}

调用方式

java代码里设置数值

java 复制代码
        float myFloat = completeProgress.floatValue(); // 将Double类型的值转换为float类型的值
        holder. circle_bar.setPercentData( myFloat , "%", null);
XML 复制代码
    <com.zx.mocab.views.CirclePercentBar
        android:id="@+id/circle_bar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_gravity="center_horizontal"
        app:arcColor="#0579FF"
        app:arcStartColor="#A5CFFF"
        app:arcWidth="10dp"
        app:centerTextColor="#222222"
        app:centerTextSize="24sp"
        app:circleRadius="40dp" />

效果图

相关推荐
冬奇Lab1 小时前
PMS核心机制:应用安装与包管理深度解析
android·源码阅读
城东米粉儿3 小时前
Android 计算滑动帧率 笔记
android
城东米粉儿4 小时前
Android Choreographer 和 looper 结合使用 监控
android
城东米粉儿4 小时前
Android inline Hook 笔记
android
城东米粉儿4 小时前
Android 防止 Printer 覆盖笔记
android
Android系统攻城狮8 小时前
Android tinyalsa深度解析之pcm_get_timestamp调用流程与实战(一百一十八)
android·pcm·tinyalsa·android hal·audio hal
yuezhilangniao10 小时前
win10环境变量完全指南:Java、Maven、Android、Flutter -含我的环境备份
android·java·maven
奔跑吧 android11 小时前
【车载Audio】【AudioHal 06】【高通音频架构】【深入浅出 Android Audio HAL:从加载到函数指针绑定的全链路解析】
android·音视频·audioflinger·aosp13·8295·audiohal·高通音频架构
无巧不成书021811 小时前
Kotlin Multiplatform (KMP) 鸿蒙开发整合实战|2026最新方案
android·开发语言·kotlin·harmonyos·kmp