Skip to content

Instantly share code, notes, and snippets.

@ardakazanci
Created February 1, 2025 05:04
Show Gist options
  • Save ardakazanci/5788e64f6155c63b0219d799b451d30a to your computer and use it in GitHub Desktop.
Save ardakazanci/5788e64f6155c63b0219d799b451d30a to your computer and use it in GitHub Desktop.
Segmented Progress with Jetpack Compose
@Composable
fun SegmentedArcProgressIndicator(
progress: Float,
strokeWidth: Float = 48f,
maxAngle: Float = 160f,
gapAngle: Float = 15f,
backgroundColor: Color = Color(0xffCBE0E8),
progressColor: Brush = Brush.linearGradient(listOf(Color(0xff83B2D1), Color(0xff106AA7)))
) {
val animatedProgress by animateFloatAsState(
targetValue = progress,
animationSpec = tween(durationMillis = 800, easing = FastOutSlowInEasing)
)
Canvas(modifier = Modifier.size(200.dp)) {
val center = Offset(size.width / 2, size.height / 2)
val radius = size.minDimension / 2 - strokeWidth / 2
val startAngle = -maxAngle / 2 - 90f
val segmentAngle = (maxAngle - gapAngle) / 2
drawSegmentArc(center, radius, strokeWidth, startAngle, segmentAngle, color = backgroundColor)
drawSegmentArc(center, radius, strokeWidth, startAngle + segmentAngle + gapAngle, segmentAngle, color = backgroundColor)
drawSegmentArc(
center, radius, strokeWidth, startAngle,
segmentAngle * min(animatedProgress * 2, 1f), brush = progressColor
)
drawSegmentArc(
center, radius, strokeWidth, startAngle + segmentAngle + gapAngle,
segmentAngle * max((animatedProgress - 0.5f) * 2, 0f), brush = progressColor
)
}
Box(
modifier = Modifier
.size(200.dp)
.padding(40.dp),
contentAlignment = Alignment.Center
) {
Text(
text = "${(progress * 100).toInt()}%",
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
color = Color.Black
)
}
}
private fun DrawScope.drawSegmentArc(
center: Offset,
radius: Float,
strokeWidth: Float,
startAngle: Float,
sweepAngle: Float,
color: Color? = null,
brush: Brush? = null
) {
if (brush != null) {
drawArc(
brush = brush,
startAngle = startAngle,
sweepAngle = sweepAngle,
useCenter = false,
topLeft = Offset(center.x - radius, center.y - radius),
size = Size(radius * 2, radius * 2),
style = Stroke(width = strokeWidth, cap = StrokeCap.Round)
)
} else if (color != null) {
drawArc(
color = color,
startAngle = startAngle,
sweepAngle = sweepAngle,
useCenter = false,
topLeft = Offset(center.x - radius, center.y - radius),
size = Size(radius * 2, radius * 2),
style = Stroke(width = strokeWidth, cap = StrokeCap.Round)
)
}
}
@Composable
fun SegmentedArcProgressScreen() {
var progress by remember { mutableFloatStateOf(0.75f) }
var strokeWidth by remember { mutableFloatStateOf(48f) }
var gapAngle by remember { mutableFloatStateOf(15f) }
var maxAngle by remember { mutableFloatStateOf(160f) }
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
SegmentedArcProgressIndicator(
progress = progress,
maxAngle = maxAngle,
strokeWidth = strokeWidth,
gapAngle = gapAngle
)
Spacer(modifier = Modifier.height(20.dp))
SliderWithLabel("Progress: ${(progress * 100).toInt()}%", progress, { progress = it }, 0f..1f)
SliderWithLabel("Stroke Width: ${strokeWidth.toInt()}", strokeWidth, { strokeWidth = it }, 10f..80f)
SliderWithLabel("Gap Angle: ${gapAngle.toInt()}°", gapAngle, { gapAngle = it }, 0f..30f)
SliderWithLabel("Max Angle: ${maxAngle.toInt()}°", maxAngle, { maxAngle = it }, 90f..360f)
}
}
@Composable
fun SliderWithLabel(label: String, value: Float, onValueChange: (Float) -> Unit, valueRange: ClosedFloatingPointRange<Float>) {
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
val color = Color(0xff83B2D1)
Text(text = label, fontSize = 16.sp, fontWeight = FontWeight.Normal)
Slider(
value = value,
onValueChange = onValueChange,
valueRange = valueRange,
modifier = Modifier.padding(horizontal = 16.dp),
colors = SliderDefaults.colors(
thumbColor = color,
activeTrackColor = color,
inactiveTrackColor = MaterialTheme.colorScheme.secondaryContainer.copy(alpha = 0.5f),
)
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment