【自定义View】Android圆饼进度条

源码

自定义属性

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="ArcProgressView">
        <attr name="android:textSize" />
        <attr name="bgBorderWidth" format="dimension" />
        <attr name="defaultContentColor" format="color" />
        <attr name="bgBorderColor" format="color" />
        <attr name="progressColor" format="color" />
        <attr name="android:textColor" />
    </declare-styleable>
</resources>

View(kotlin)源码

kotlin 复制代码
package com.example.test

import android.content.Context
import android.content.res.Resources
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Rect
import android.util.AttributeSet
import android.util.TypedValue
import android.view.View
import kotlin.math.roundToInt

class ArcProgressView : View {
    constructor(context: Context?) : super(context)
    constructor(context: Context?, attrs: AttributeSet?) : this(context, attrs, 0)
    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    ) {
        val obtainStyledAttributes =
            context?.obtainStyledAttributes(attrs, R.styleable.ArcProgressView)

        obtainStyledAttributes?.let {
            textSize = it.getDimensionPixelSize(
                R.styleable.ArcProgressView_android_textSize,
                textSize
            )

            strokeWidth = it.getDimensionPixelSize(
                R.styleable.ArcProgressView_bgBorderWidth,
                strokeWidth.roundToInt()
            ).toFloat()
            defaultContentColor = it.getColor(
                R.styleable.ArcProgressView_defaultContentColor,
                defaultContentColor
            )
            bgBorderColor =
                it.getColor(R.styleable.ArcProgressView_bgBorderColor, bgBorderColor)
            progressColor =
                it.getColor(R.styleable.ArcProgressView_progressColor, progressColor)
            textColor =
                it.getColor(R.styleable.ArcProgressView_android_textColor, textColor)

        }

        obtainStyledAttributes?.recycle()
    }

    val paint = Paint(Paint.ANTI_ALIAS_FLAG)
    var strokeWidth = dpToPx(0.5f).toFloat();
    var textSize = spToPx(10f).roundToInt()
    var defaultContentColor = Color.parseColor("#FFF7ED")
    var bgBorderColor = Color.parseColor("#FAD29D")
    var progressColor = Color.parseColor("#FAD29D")
    var textColor = Color.parseColor("#FA940F")

    private var progress: Int = 0
        set(value) {
            field = value
            invalidate()
        }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        drawBackground(canvas)
        drawProgress(canvas)
    }

    private fun dpToPx(dp: Float): Int {
        return (Resources.getSystem().displayMetrics.density * dp + 0.5f).roundToInt()
    }

    private fun spToPx(sp: Float): Float {
        return TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_SP,
            sp,
            Resources.getSystem().displayMetrics
        )
    }

    private fun drawBackground(canvas: Canvas) {

        paint.strokeWidth = strokeWidth
        paint.style = Paint.Style.FILL
        paint.color = defaultContentColor
        canvas.drawOval(
            0f + strokeWidth / 2,
            0f + strokeWidth / 2,
            width.toFloat() - strokeWidth / 2,
            height.toFloat() - strokeWidth / 2,
            paint
        )
        paint.style = Paint.Style.STROKE
        paint.color = bgBorderColor
        canvas.drawOval(
            0f + strokeWidth / 2,
            0f + strokeWidth / 2,
            width.toFloat() - strokeWidth / 2,
            height.toFloat() - strokeWidth / 2,
            paint
        )

    }

    val textBound = Rect()

    private fun drawProgress(canvas: Canvas) {
        paint.style = Paint.Style.FILL
        paint.color = progressColor

        paint.textSize = textSize.toFloat()

        val progressStr = "$progress%"
        paint.getTextBounds(progressStr, 0, progressStr.length, textBound)
        val halfTextWidth = textBound.width() / 2f
        val halfTextHeight = textBound.height() / 2f
        val progressAngle = progress * 3.6f

        val halfWidth = width.toFloat() / 2f
        val halfHeight = height.toFloat() / 2f

        canvas.drawArc(
            0f,
            0f,
            width.toFloat(),
            height.toFloat(),
            270f,
            progressAngle,
            true,
            paint
        )

        paint.isFakeBoldText = true
        paint.color = textColor
        paint.textAlign = Paint.Align.LEFT
        canvas.drawText(
            progressStr,
            halfWidth - halfTextWidth,
            halfHeight - halfTextHeight + textBound.height(),
            paint
        )
    }

    fun updateProgress(progress: Int) {
        this.progress = progress
    }


}

Activity布局

xml 复制代码
  <com.example.test.ArcProgressView
        android:layout_margin="12dp"
        android:id="@+id/progress"
        android:textSize="24sp"
        android:textColor="@color/black"
        android:layout_width="100dp"
        android:layout_height="100dp"/>

Activity更新进度

kotlin 复制代码
progress ++
runOnUiThread({
    progressView.updateProgress(progress)
})

效果图

相关推荐
CYRUS_STUDIO8 小时前
深入 Android syscall 实现:内联汇编系统调用 + NDK 汇编构建
android·操作系统·汇编语言
死也不注释9 小时前
【第一章编辑器开发基础第一节绘制编辑器元素_6滑动条控件(6/7)】
android·编辑器
程序员JerrySUN11 小时前
Linux 文件系统实现层详解:原理、结构与驱动衔接
android·linux·运维·数据库·redis·嵌入式硬件
2501_9160137411 小时前
iOS 加固工具使用经验与 App 安全交付流程的实战分享
android·ios·小程序·https·uni-app·iphone·webview
南棱笑笑生11 小时前
20250715给荣品RD-RK3588开发板刷Android14时打开USB鼠标
android·计算机外设
hy.z_77713 小时前
【数据结构】反射、枚举 和 lambda表达式
android·java·数据结构
幻雨様13 小时前
UE5多人MOBA+GAS 20、添加眩晕
android·ue5
没有了遇见14 小时前
开源库 XPopup 资源 ID 异常修复:从发现 BUG 到本地 AAR 部署全流程
android
雮尘14 小时前
一文读懂 Android 屏幕适配:从基础到实践
android·前端
用户20187928316714 小时前
浅谈焦点冲突导致异常背景色的机制
android