You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为CircularProgressIndicator设置自定义半圆缺口形状?

实现带缺口的半圆进度指示器(基于CircularProgressIndicator)

要实现带缺口的半圆进度样式,不需要完全重写整个视图,可以通过自定义Drawable或者扩展CircularProgressIndicator两种方式来实现,下面是具体方案:

方案一:自定义带缺口的半圆进度Drawable

直接创建一个Drawable,手动绘制带缺口的背景和进度圆弧,完全控制样式:

class GapSemiCircleProgressDrawable : Drawable() {
    private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        style = Paint.Style.STROKE
        strokeWidth = 12.dpToPx() // 进度条宽度,可自行调整
    }
    private var progress = 0f // 0-1范围的进度值
    private val gapAngle = 30f // 缺口角度,按需调整
    // 计算半圆起始角度(从下方开始,预留缺口一半的空间)
    private val startAngle = 180f + gapAngle / 2
    // 计算可填充的圆弧角度(半圆减去缺口角度)
    private val sweepAngle = 180f - gapAngle

    override fun onDraw(canvas: Canvas) {
        val bounds = bounds
        val centerX = bounds.centerX().toFloat()
        val centerY = bounds.centerY().toFloat()
        val radius = min(bounds.width(), bounds.height()) / 2f - paint.strokeWidth / 2

        // 绘制灰色背景圆弧
        paint.color = Color.LTGRAY
        canvas.drawArc(
            centerX - radius, centerY - radius,
            centerX + radius, centerY + radius,
            startAngle, sweepAngle, false, paint
        )

        // 绘制蓝色进度圆弧
        paint.color = Color.BLUE
        val progressSweep = sweepAngle * progress
        canvas.drawArc(
            centerX - radius, centerY - radius,
            centerX + radius, centerY + radius,
            startAngle, progressSweep, false, paint
        )
    }

    // 设置进度(0-1)
    fun setProgress(progress: Float) {
        this.progress = progress.coerceIn(0f, 1f)
        invalidateSelf()
    }

    override fun setAlpha(alpha: Int) {
        paint.alpha = alpha
        invalidateSelf()
    }

    override fun setColorFilter(colorFilter: ColorFilter?) {
        paint.colorFilter = colorFilter
        invalidateSelf()
    }

    override fun getOpacity(): Int = PixelFormat.TRANSLUCENT

    // DP转PX工具方法
    private fun Int.dpToPx(): Float = this * Resources.getSystem().displayMetrics.density
}

使用方式

在代码中初始化Drawable并绑定到View,更新进度:

// 初始化Drawable
val progressDrawable = GapSemiCircleProgressDrawable()
// 绑定到ImageView或自定义View
progressImageView.setImageDrawable(progressDrawable)
// 更新进度为70%
progressDrawable.setProgress(0.7f)

方案二:扩展CircularProgressIndicator复用原有逻辑

如果想复用CircularProgressIndicator的进度动画、属性配置等逻辑,可以直接扩展它,重写绘制时的角度参数:

class GapSemiCircleProgressIndicator @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : CircularProgressIndicator(context, attrs, defStyleAttr) {
    private val gapAngle = 30f // 缺口角度,按需调整

    override fun onDraw(canvas: Canvas) {
        // 临时替换起始角度和扫过角度,绘制带缺口的半圆
        val originalStart = startAngle
        val originalSweep = sweepAngle
        
        startAngle = 180f + gapAngle / 2
        sweepAngle = 180f - gapAngle
        
        super.onDraw(canvas)
        
        // 恢复原有参数,避免影响其他逻辑
        startAngle = originalStart
        sweepAngle = originalSweep
    }
}

使用方式

直接在布局中引用自定义View,通过原有属性配置样式:

<com.yourpackage.GapSemiCircleProgressIndicator
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:progress="70"
    app:indicatorColor="@color/blue"
    app:trackColor="@color/light_gray"
    app:strokeWidth="12dp"/>

两种方案都能实现带缺口的半圆进度效果,进度会自动按比例填充到有效圆弧范围内。如果需要更复杂的样式自定义,优先选择方案一;如果想复用系统控件的现有能力,方案二更高效。

内容的提问来源于stack exchange,提问作者Avinta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 07:10:58