自动将文本大小缩放到边界框区域

问题描述 投票:0回答:1

我试图根据矩形的高度和宽度将文本居中,但它偏离中心。此外,我需要根据该矩形的大小调整文本。但是,我没有找到很好的解决方案。

有人知道错误可能出在哪里吗?

结果:

enter image description here

我的帮助代码:

@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)
    }
}
android kotlin android-jetpack-compose android-canvas
1个回答
0
投票

您使用固定值 2.5 计算用于使文本居中的 Y 坐标,这可能会导致文本偏离中心。

@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 currentSize = textMeasurer.measure(text).size
    val desiredSize = Size(boundingBox.width(), boundingBox.height())

    // Calculate the font size to fit both width and height
    val font = calculateScaledFontSize(currentSize, desiredSize)

    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,
    )

    // Draw bounding box
    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()),
    )

    // Draw text centered within the bounding box
    drawText(
        textMeasurer = textMeasurer,
        style = style,
        text = text.uppercase(),
        // Center the text vertically and horizontally
        topLeft = Offset(
            x = boundingBox.left + (boundingBox.width() - currentSize.width) / 2,
            y = boundingBox.top + (boundingBox.height() - currentSize.height) / 2
        )
    )
}

//更新字体缩放功能

private fun calculateScaledFontSize(
        currentSize: Size,
        desiredSize: Size,
    ): Float {
        val widthScaleFactor = desiredSize.width / currentSize.width
        val heightScaleFactor = desiredSize.height / currentSize.height
        // Choose the smaller scale factor to ensure the text fits within the bounding box
        val scaleFactor = min(widthScaleFactor, heightScaleFactor)
        // Return scaled font size
        return 12.sp.toPx() * scaleFactor // Adjust the base font size as needed
    }

我已经用代码中的示例更新了您的代码,请尝试一下。

© www.soinside.com 2019 - 2024. All rights reserved.