I’m trying to center a text within a rectangle according to its height and width, but it comes out off-center. Additionally, I need the text to adjust according to the size of this rectangle. However, I’m not finding very good solutions.
Would anyone know where the error might be?
Result:
My code for help:
@Composable
internal fun ScreenShotDrawSpeech(
bubbleDomain: ImmutableList<SpeechBubbleDomain>,
modifier: Modifier = Modifier,
) {
val textMeasurer = rememberTextMeasurer()
val zoom = rememberZoomableState()
Canvas(
modifier = modifier
.fillMaxSize()
.zoomable(zoom),
onDraw = {
bubbleDomain.forEach { prediction ->
drawSpeechBoundingBox(text = prediction.originalText, boundingBox = prediction.rect, textMeasurer = textMeasurer)
}
},
)
}
private fun DrawScope.drawSpeechBoundingBox(
boundingBox: Rect,
text: String,
textMeasurer: TextMeasurer,
) {
val currentWidth = textMeasurer.measure(text).size.width
val currentHeight = textMeasurer.measure(text).size.height
val desiredWidth = boundingBox.width()
val desiredHeight = boundingBox.height()
val centerTextY = (boundingBox.height() - currentHeight) / 2.5
val font = calculateScaledFontSize(
currentWidth = currentWidth,
currentHeight = currentHeight,
desiredWidth = desiredWidth,
desiredHeight = desiredHeight,
minFontSize = 12.sp.toPx(),
maxFontSize = 14.sp.value,
text = text,
)
val style = TextStyle(
fontSize = font.sp,
fontFamily = FontFamily(Font(R.font.manga_master_bb)),
color = Color.Black,
background = Color.White,
textAlign = TextAlign.Center,
fontWeight = FontWeight.Bold,
)
drawOval(
color = Color.White,
topLeft = Offset(boundingBox.left.toFloat(), boundingBox.top.toFloat()),
size = Size(boundingBox.width().toFloat(), boundingBox.height().toFloat()),
)
drawOval(
color = Color.Black,
style = Stroke(width = 2f),
topLeft = Offset(boundingBox.left.toFloat(), boundingBox.top.toFloat()),
size = Size(boundingBox.width().toFloat(), boundingBox.height().toFloat()),
)
drawText(
textMeasurer = textMeasurer,
style = style,
size = Size(boundingBox.width().toFloat(), boundingBox.height().toFloat()),
topLeft = Offset(
boundingBox.left.toFloat(),
boundingBox.top.toFloat() + centerTextY.toFloat(),
),
text = text.uppercase(),
)
}
@Suppress("LongParameterList")
private fun calculateScaledFontSize(
currentWidth: Int,
currentHeight: Int,
desiredWidth: Int,
desiredHeight: Int,
minFontSize: Float,
maxFontSize: Float,
text: String,
): Float {
val widthScaleFactor = minFontSize * desiredWidth / currentWidth
val heightScaleFactor = minFontSize * desiredHeight / currentHeight
return if (min(widthScaleFactor, heightScaleFactor) >= maxFontSize) {
if (text.length <= 10) {
min(widthScaleFactor, heightScaleFactor) / 3
} else {
min(widthScaleFactor, heightScaleFactor) / 2
}
} else {
min(widthScaleFactor, heightScaleFactor)
}
}