如何实现Android可穿戴设备矩形屏幕沿边框环绕的自定义进度条?
问题原因分析
你当前的实现出现旋转矩形而非进度条的核心原因是:
- 你使用的
<rotate>标签是对整个矩形描边做360度旋转,Android原生ProgressBar的进度值仅会控制rotate的旋转角度,不会裁剪进度显示区域 - 你没有区分「背景层(完整边框)」和「进度层(已完成部分的边框)」两层结构,这是类环形进度条的标准实现逻辑
解决方案1:自定义Drawable实现环绕矩形边框进度(推荐,完全适配方形/矩形表盘需求)
这个方案灵活性最高,完全不需要第三方依赖,可以完美实现沿着方形/矩形边框环绕的进度效果,逻辑和环形进度条完全一致:
- 新建
RectBorderProgressDrawable.kt文件,代码如下:
import android.graphics.* import android.graphics.drawable.Drawable import android.util.TypedValue import android.content.res.Resources class RectBorderProgressDrawable( private val borderWidthDp: Float = 2f, private val cornerRadiusDp: Float = 8f, private val bgColor: Int = Color.LTGRAY, private val progressColor: Int = Color.BLUE ) : Drawable() { private val borderWidth = dp2px(borderWidthDp) private val cornerRadius = dp2px(cornerRadiusDp) private val bgPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { style = Paint.Style.STROKE strokeWidth = borderWidth color = bgColor } private val progressPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { style = Paint.Style.STROKE strokeWidth = borderWidth color = progressColor strokeCap = Paint.Cap.ROUND } private val borderPath = Path() private val pathMeasure = PathMeasure() private var progress = 0f // 取值范围0-1 override fun onBoundsChange(bounds: Rect) { super.onBoundsChange(bounds) // 边框向内缩进半个线宽,避免描边被裁剪 val insetRect = RectF(bounds).apply { inset(borderWidth / 2, borderWidth / 2) } borderPath.reset() borderPath.addRoundRect(insetRect, cornerRadius, cornerRadius, Path.Direction.CW) pathMeasure.setPath(borderPath, false) } override fun draw(canvas: Canvas) { // 绘制完整的背景边框 canvas.drawPath(borderPath, bgPaint) // 绘制对应进度的边框片段 if (progress > 0) { val progressPath = Path() pathMeasure.getSegment(0f, pathMeasure.length * progress, progressPath, true) canvas.drawPath(progressPath, progressPaint) } } override fun setAlpha(alpha: Int) { bgPaint.alpha = alpha progressPaint.alpha = alpha invalidateSelf() } override fun setColorFilter(colorFilter: ColorFilter?) { bgPaint.colorFilter = colorFilter progressPaint.colorFilter = colorFilter invalidateSelf() } override fun getOpacity(): Int = PixelFormat.TRANSLUCENT // 对外暴露设置进度的方法 fun setProgress(progress: Float) { this.progress = progress.coerceIn(0f, 1f) invalidateSelf() } private fun dp2px(dp: Float): Float { return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, Resources.getSystem().displayMetrics) } }
- 使用方式:
// 给目标ProgressBar设置自定义Drawable val progressDrawable = RectBorderProgressDrawable() progressBar.progressDrawable = progressDrawable // 更新进度,传入0-1的数值对应0%-100%进度 progressDrawable.setProgress(0.75f)
解决方案2:纯XML实现(适合简单单边矩形进度需求,无需自定义代码)
如果你的需求仅为单边横向/纵向矩形进度,不需要环绕边框效果,可以用如下XML实现:
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 背景层:完整的灰色边框 --> <item android:id="@android:id/background"> <shape android:shape="rectangle"> <stroke android:width="2dp" android:color="@color/mit_light_grey" /> <corners android:radius="8dp" /> </shape> </item> <!-- 进度层:按进度裁剪显示的彩色边框 --> <item android:id="@android:id/progress"> <clip android:clipOrientation="horizontal" android:gravity="left"> <shape android:shape="rectangle"> <stroke android:width="2dp" android:color="@color/mit_blue" /> <corners android:radius="8dp" /> </shape> </clip> </item> </layer-list>
直接将上述文件设置为ProgressBar的progressDrawable属性即可,系统会自动根据进度值控制裁剪范围实现进度效果。
内容的提问来源于stack exchange,提问作者Mohamed El Kayal
相关产品推荐
相关产品推荐

