Ayush Shakya
Ayush Shakya

Reputation: 183

Blank space when creating a custom text rendering composable

I was trying to create custom text rendering composable using the the Canvas composable. However, I don't understand how TextMeasurer is calculating the final height of the composable.

Here is a minimal example of what I have tried till now.

@Composable
fun ShyText(
    text: String,
    modifier: Modifier = Modifier
) {
    val textMeasurer = rememberTextMeasurer()
    val measuredText =
        textMeasurer.measure(
            AnnotatedString(text),
            overflow = TextOverflow.Ellipsis,
            constraints = Constraints.fixedWidth(1080),
            style = TextStyle(
                fontSize = 18.sp,
            )
        )
    Canvas(
        Modifier
            .fillMaxWidth()
            .height(measuredText.size.height.dp) //I think the bug is coming from this line.
            .background(Color.DarkGray)
    ) {
        drawText(
            measuredText,
        )

    }
}

Here is how the composable is used.

ShyTextTheme {
      Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
          Column(Modifier.padding(innerPadding)) {
                ShyText(
                   text = sampletext,
                )
                Text("text")
                }
            }
}

This is the current result Screenshot of the text composable with a large blank space below it

I am trying to render without the blank space above "text" and the final line of the paragraph. I would like to know why the blank space is being rendered. (The grey background is just for testing)

Upvotes: 1

Views: 65

Answers (2)

Thracian
Thracian

Reputation: 67238

That's not bug. What's returned from measuredText.size.height is in pixels. But you set height in dp directly from pixel value by adding dp end of it. density independent pixels are calculated with pixel value / density. If you get 200px from measured height on a device with 2.0 density it should be 100.dp, on a device with 4.0 density it should be 50.dp.

You just need to change it to

val density = LocalDensity.current
val heightDp = with(density){measuredText.size.height.toDp()}
Canvas(
    Modifier
        .fillMaxWidth()
        .height(heightDp) //I think the bug is coming from this line.
        .background(Color.DarkGray)
) {
    drawText(
        measuredText,
    )

}

This is how conversion is done with toDp()

/** Convert a [Float] pixel value to a Dp */
@Stable
fun Float.toDp(): Dp = (this / density).dp

Upvotes: 1

alson
alson

Reputation: 59

I don't not if this might help, I'm currently learning android studio, language in use is java. If there is a view on the xml file you just drop the element you wish to place, e.g text, button e.t.c, after which you place your mouse on the borders of the element and move an arrow line toward the edge of the window(phone) for both sides and it will usually be centered. It doesn't have to be the edge it could also be an element.

Upvotes: 0

Related Questions