androidandroid-jetpack-composeandroid-jetpack-compose-text

Jetpack Compose: Use different layout if text does not fit?


Say I have a fixed size rectangle with some text inside. Since the user can change the font size from the System - Accessibility settings on the device, the font might not fit inside the fixed sized rectangle. If this happen, we would like to render the text outside the rectangle instead.

AFAIK I should somehow measure the text's width (for example) and see if it fits inside the rectangle and if not, layout the components in a different manner.

How would I do this in Jetpack Compose?

So with this pseudo code, if text does not fit inside the Box I would like to lay out the text below it, thus introducing a Column etc instead.

@Composable
fun myView() {
  val text = Text("Some text")
  Box(modifier = Modifier.size(40.dp)) {
      text
  }
}

Solution

  • Using onTextLayout you can get size of drawn text.

    To prevent actually drawing it while calculating the size you can use drawWithContent modifier.

    var textSize by remember { mutableStateOf<IntSize?>(null) }
    val density = LocalDensity.current
    val maxDimensionDp = remember(textSize) {
        textSize?.let { textSize ->
            with(density) {
                maxOf(textSize.width, textSize.height).toDp()
            }
        }
    }
    val textComposable = @Composable {
        Text(
            "Some text",
            onTextLayout = {
                textSize = it.size
            },
            modifier = Modifier.drawWithContent {
                if (textSize != null) {
                    drawContent()
                }
            }
        )
    }
    when {
        maxDimensionDp == null -> {
            // calculating size.
            // because of drawWithContent it's not gonna be drawn
            textComposable()
        }
        maxDimensionDp < 40.dp -> {
            Box(modifier = Modifier.size(40.dp).background(Color.Red)) {
                textComposable()
            }
        }
        else -> {
            Column(modifier = Modifier.background(Color.Green)) {
                textComposable()
            }
        }
    }