如何在Android Jetpack Compose中实现类似圆形进度条的矩形边框进度条
实现矩形边框进度指示器(类似圆形进度条样式)
要实现矩形边框的进度指示器,你可以通过Compose的Canvas自定义绘制,以下是完整实现方案:
自定义进度指示器组件
import androidx.compose.foundation.Canvas import androidx.compose.foundation.layout.size import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Path import androidx.compose.ui.graphics.StrokeCap import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp @Composable fun RectangularBorderProgressIndicator( progress: Float, // 进度值,范围0f-1f strokeWidth: Dp = 10.dp, color: Color = MaterialTheme.colorScheme.primary, backgroundColor: Color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.1f), modifier: Modifier = Modifier ) { Canvas(modifier = modifier) { val strokeWidthPx = strokeWidth.toPx() val halfStroke = strokeWidthPx / 2 // 绘制区域:减去边框宽度的一半,避免边框超出容器 val drawSize = Size( width = size.width - strokeWidthPx, height = size.height - strokeWidthPx ) val topLeft = Offset(halfStroke, halfStroke) val bottomRight = Offset(topLeft.x + drawSize.width, topLeft.y + drawSize.height) // 绘制背景边框 drawRect( color = backgroundColor, topLeft = topLeft, size = drawSize, style = Stroke(width = strokeWidthPx) ) // 计算总周长和进度对应的长度 val perimeter = 2 * (drawSize.width + drawSize.height) val progressLength = perimeter * progress.coerceIn(0f, 1f) // 构建进度路径 val path = Path().apply { moveTo(topLeft.x, topLeft.y) var remainingLength = progressLength // 绘制顶部边 val topEdgeLength = drawSize.width if (remainingLength <= topEdgeLength) { lineTo(topLeft.x + remainingLength, topLeft.y) remainingLength = 0f } else { lineTo(bottomRight.x, topLeft.y) remainingLength -= topEdgeLength } // 绘制右侧边 val rightEdgeLength = drawSize.height if (remainingLength > 0 && remainingLength <= rightEdgeLength) { lineTo(bottomRight.x, topLeft.y + remainingLength) remainingLength = 0f } else if (remainingLength > 0) { lineTo(bottomRight.x, bottomRight.y) remainingLength -= rightEdgeLength } // 绘制底部边 val bottomEdgeLength = drawSize.width if (remainingLength > 0 && remainingLength <= bottomEdgeLength) { lineTo(bottomRight.x - remainingLength, bottomRight.y) remainingLength = 0f } else if (remainingLength > 0) { lineTo(topLeft.x, bottomRight.y) remainingLength -= bottomEdgeLength } // 绘制左侧边 val leftEdgeLength = drawSize.height if (remainingLength > 0 && remainingLength <= leftEdgeLength) { lineTo(topLeft.x, bottomRight.y - remainingLength) } } // 绘制进度边框 drawPath( path = path, color = color, style = Stroke( width = strokeWidthPx, cap = StrokeCap.Round // 可选:设置端点为圆角,和CircularProgressIndicator风格统一 ) ) } }
使用示例
替换你原来的CircularProgressIndicator,直接调用自定义组件即可:
RectangularBorderProgressIndicator( progress = 0.75f, // 75%进度 strokeWidth = 10.dp, color = Color.Red, modifier = Modifier.size(200.dp) )
关键说明
- 背景边框:先绘制一层半透明的完整矩形边框,作为未完成部分的视觉参考
- 进度计算:通过矩形周长乘以进度值,确定需要绘制的边框长度,再分四个边依次绘制
- StrokeCap.Round:可选启用,让边框端点和圆形进度条风格保持一致
- 参数兼容:保留了和
CircularProgressIndicator类似的参数(progress、strokeWidth、color),方便替换
内容的提问来源于stack exchange,提问作者Mohammed Ragab
相关产品推荐
相关产品推荐

