Busco dibujar un arco en un lienzo en Jetpack Compose con un pequeño círculo en el borde del progreso como esta imagen:
Encontré cómo dibujar la barra de progreso con un lienzo de arco, pero aún no sé cómo dibujar el círculo para que coincida con el borde de la línea del arco. Este es mi código de progreso:
@Composable fun ComposeCircularProgressBar( modifier: Modifier = Modifier, percentage: Float, fillColor: Color, backgroundColor: Color, strokeWidth: Dp ) { Canvas( modifier = modifier .padding(strokeWidth / 2) ) { // Background Line drawArc( color = backgroundColor, 135f, 270f, false, style = Stroke(strokeWidth.toPx(), cap = StrokeCap.Butt) ) // Fill Line drawArc( color = fillColor, 135f, 270f * percentage, false, style = Stroke(strokeWidth.toPx(), cap = StrokeCap.Round) ) } } Notado: por ahora sé que dibujar ese círculo es con Canvas.drawCircle(offset = Offset) pero aún no sé cómo calcular el Offset(x,y) para que coincida con el borde del progreso.
Este fragmento de código a continuación generará el arco con el punto circular en función del porcentaje que proporcione. Obtuviste bien la mayor parte de la parte, solo se trataba de resolver la ecuación matemática para encontrar el punto en el círculo.
Asumí el radio del círculo como Altura/2 del widget.
Como no estamos dibujando el círculo completo, el ángulo inicial es de 140 grados y el ángulo de barrido máximo es de 260 grados. (Encontré esto por golpe y prueba, para que se vea lo más cerca posible de su imagen)
Ahora, para dibujar el pequeño círculo blanco, el centro, también conocido como desplazamiento , debe estar en (x, y), donde x e y están dados por la fórmula
x = radio * sin (ángulo en radianes) y = radio * cos (ángulo en radianes)
@Composable fun ComposeCircularProgressBar( modifier: Modifier = Modifier, percentage: Float, fillColor: Color, backgroundColor: Color, strokeWidth: Dp ) { Canvas( modifier = modifier .size(150.dp) .padding(10.dp) ) { // Background Line drawArc( color = backgroundColor, 140f, 260f, false, style = Stroke(strokeWidth.toPx(), cap = StrokeCap.Round), size = Size(size.width, size.height) ) drawArc( color = fillColor, 140f, percentage * 260f, false, style = Stroke(strokeWidth.toPx(), cap = StrokeCap.Round), size = Size(size.width, size.height) ) var angleInDegrees = (percentage * 260.0) + 50.0 var radius = (size.height / 2) var x = -(radius * sin(Math.toRadians(angleInDegrees))).toFloat() + (size.width / 2) var y = (radius * cos(Math.toRadians(angleInDegrees))).toFloat() + (size.height / 2) drawCircle( color = Color.White, radius = 5f, center = Offset(x, y) ) } }Aquí hay algunos ejemplos que probé con
@Preview @Composable fun PreviewPorgressBar() { ComposeCircularProgressBar( percentage = 0.80f, fillColor = Color(android.graphics.Color.parseColor("#4DB6AC")), backgroundColor = Color(android.graphics.Color.parseColor("#90A4AE")), strokeWidth = 10.dp ) } @Preview @Composable fun PreviewPorgressBar() { ComposeCircularProgressBar( percentage = 0.45f, fillColor = Color(android.graphics.Color.parseColor("#4DB6AC")), backgroundColor = Color(android.graphics.Color.parseColor("#90A4AE")), strokeWidth = 10.dp ) } @Preview @Composable fun PreviewPorgressBar() { ComposeCircularProgressBar( percentage = 1f, fillColor = Color(android.graphics.Color.parseColor("#4DB6AC")), backgroundColor = Color(android.graphics.Color.parseColor("#90A4AE")), strokeWidth = 10.dp ) }