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
Expected Output
When text is "Extremely high"
When text is "Very high"
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
)
)
}