0

I want to align my drawText centre of view in my canvas. I draw my Image view with the help of this answer. Now I want to drawText at above, but my Text is in centre of my view. It's little bit complicated but I'll show you in image.

@OptIn(ExperimentalTextApi::class)
@Composable
fun DrawProgressBar() {
    val rangeComposition = RangeComposition()
    val itemLst = rangeComposition.bpExplained
    val brush = Brush.horizontalGradient(listOf(Color.Red, Color.Blue))
    val progressBarPointer = rangeComposition.findReadingWithPointer(142, 90).second
    val textMeasurer = rememberTextMeasurer()
    textMeasurer.measure(text = AnnotatedString("Extremely high"))
    Canvas(
        modifier = Modifier
            .fillMaxWidth()
            .height(60.dp)
            .background(Color.White)
    ) {

        //triangle size

        val rectSize = Size(12.dp.toPx(), 9.dp.toPx())
        val strokeWidth = 8.dp
        val canvasWidth = size.width
        val canvasHeight = size.height
        val strokeWidthPx = density.run { strokeWidth.toPx() }
        val dashedPathEffect =
            PathEffect.dashPathEffect(floatArrayOf(canvasHeight / 38, canvasHeight / 38), 0f)
        val rect = Rect(Offset.Zero, rectSize)
        val trianglePath = Path().apply {
            moveTo(rect.bottomCenter.x, rect.bottomCenter.y)
            lineTo(rect.topRight.x, rect.topRight.y)
            lineTo(rect.topLeft.x, rect.topLeft.y)
            close()
        }
        val progressBarPointerInPixel = (progressBarPointer / 100f) * canvasWidth

        drawIntoCanvas { canvas ->
            // I want to fix this in centre of drawOutline
            drawText(
                textMeasurer = textMeasurer,
                text = "Extremely high",
                topLeft = Offset((progressBarPointerInPixel), 2.dp.toPx()),
                style = TextStyle(fontSize = 12.sp)
            )

            translate(progressBarPointerInPixel, 20.dp.toPx()) {
                canvas.drawOutline(
                    outline = Outline.Generic(trianglePath),
                    paint = Paint().apply {
                        color = Color.DarkGray
                        pathEffect = PathEffect.cornerPathEffect(rect.maxDimension / 3)
                    }
                )
            }

            drawLine(
                start = Offset(x = 0f, y = (canvasHeight / 4) * 3),
                end = Offset(x = canvasWidth, y = (canvasHeight / 4) * 3),
                color = Color.Gray,
                strokeWidth = strokeWidthPx,
                cap = StrokeCap.Round,
            )
            drawLine(
                color = Color.White,
                start = Offset(x = progressBarPointerInPixel, y = (canvasHeight / 4) * 3),
                end = Offset(x = progressBarPointerInPixel + strokeWidthPx / 2, y = (canvasHeight / 4) * 3),
                strokeWidth = strokeWidthPx,
            )
            drawLine(
                brush = brush,
                start = Offset(x = 0f, y = (canvasHeight / 4) * 3),
                end = Offset(x = progressBarPointerInPixel, y = (canvasHeight / 4) * 3),
                strokeWidth = strokeWidthPx,
                cap = StrokeCap.Round,
            )
            drawArc(
                topLeft = Offset(
                    x = progressBarPointerInPixel,
                    y = ((canvasHeight / 4) * 3) - strokeWidthPx / 2
                ),
                size = Size(strokeWidthPx, strokeWidthPx),
                color = Color.White,
                startAngle = -90f,
                sweepAngle = 180f,
                useCenter = true
            )
            itemLst.forEachIndexed { index, rangeItem ->
                val endPointInPixel = (rangeItem.endPoint / 100f) * canvasWidth
                if (index != itemLst.lastIndex) {
                    drawLine(
                        start = Offset(x = endPointInPixel, y = 30.dp.toPx()),
                        end = Offset(x = endPointInPixel, y = canvasHeight),
                        color = Color.Black,
                        strokeWidth = 1.2.dp.toPx(),
                        pathEffect = dashedPathEffect
                    )
                }
            }
        }
    }
}

Actual Output

enter image description here

Expected Output

When text is "Extremely high"

enter image description here

When text is "Very high"

enter image description here

Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
Kotlin Learner
  • 3,995
  • 6
  • 47
  • 127

1 Answers1

1

You are using the same horizontal offset for the Text and the triangle.
The right horizontal offset for the Text is the center of triangle - textWidth/2.

You can use:

    Canvas(modifier = Modifier.fillMaxSize()){
        
        val rectSize = Size (60f,60f)
        //... your code

        val triangleLeftOffset = 150f

        drawIntoCanvas { canvas ->

            translate (triangleLeftOffset,70f){
                canvas.drawOutline(
                    outline = Outline.Generic(trianglePath),
                    //...
                )
            }
        }


        val textLayoutResult: TextLayoutResult =
            textMeasurer.measure(
                text = AnnotatedString("Extremely high"),
                style = TextStyle(color = Color.Blue, fontSize = 20.sp)
            )
        val textSize = textLayoutResult.size

        val triangleCenterX = triangleLeftOffset + rectSize.width/2

        drawText(
            textLayoutResult = textLayoutResult,
            topLeft = Offset(
                x  = triangleCenterX - textSize.width/2f,
                y = 0f
            )
        )
    }

enter image description here

Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841