Search code examples
androidandroid-jetpack-composeandroid-canvasandroid-jetpack-compose-canvas

How do I create this circular shape in Jetpack Compose?


I have a Pomodoro app and want to use this circular shape. This shape changes according to time value. Dots on the outside are not important, I want an inside and circular shape on my app. I used Jetpack Compose with drawArc and Canvas, but can't achieve it.

I want something like this:

circle design

Here are my codes:

Canvas(modifier.offset(y = 10.dp)) {
    drawArc(
        color = inactiveBarColor,
        startAngle = 90f,      
        sweepAngle = 90f,       
        useCenter = false,
        size = Size(size.width.toFloat(), size.height.toFloat()),
        style = Stroke(strokeWidth.toPx(), cap = StrokeCap.Round)
   )
   drawArc(
        color = activeBarColor,
        startAngle = 0f,      
        sweepAngle = 90f,
        useCenter = false,
        size = Size(size.width.toFloat(), size.height.toFloat()),
        style = Stroke(strokeWidth.toPx(), cap = StrokeCap.Round)
   )
}

Values of angles are random, and just used for demonstrating


Solution

  • You can draw it like this. By changing values you can build exact clock shape. And you need to convert from time to angle for sweep angle in your code.

    enter image description here

     @Preview
    @Composable
    private fun ClockArcSample() {
        Column {
    
            var sweepAngle by remember {
                mutableStateOf(90f)
            }
    
            Canvas(
                modifier = Modifier
                    .fillMaxWidth()
                    .background(Color.Red)
                    .aspectRatio(1f)
            ) {
                val canvasWidth = size.width
                val arcDiameter = canvasWidth * .55f
    
                drawCircle(
                    color = Color.White,
                    style = Stroke(canvasWidth * 0.04f),
                    radius = canvasWidth * .35f
                )
    
                drawArc(
                    color = Color.White,
                    270f,
                    sweepAngle,
                    true,
                    topLeft = Offset((canvasWidth - arcDiameter) / 2, (canvasWidth - arcDiameter) / 2),
                    size = Size(arcDiameter, arcDiameter)
                )
    
                val strokeWidth = 2.dp.toPx()
                for (i in 0..360 step 6) {
                    rotate(i.toFloat()) {
                        drawLine(
                            color = Color.White,
                            strokeWidth = strokeWidth,
                            start = Offset(
                                x = canvasWidth * 0.90f,
                                y = center.y
                            ),
                            end = Offset(
                                x = canvasWidth * 0.93f,
                                y = center.y
                            ),
                            cap = StrokeCap.Round
                        )
                    }
                }
            }
    
            Slider(
                value = sweepAngle,
                onValueChange = { sweepAngle = it },
                valueRange = 0f..360f
            )
        }
    }