Prevent Text in Jetpack Compose from enlarging when device font size is increases

Viewed 1771

I have a screen in my app which displays a timer. If the user decides to increase the font size in the device settings menu then the text becomes too large for the layout and it begins to wrap. This is not an issue for my other screens that are more text heavy. For this screen - and only this screen - I would prefer to prevent the timer text from increasing in size if accessibility options are used.

Well formatted compose page Device font settings Poorly formatted compose page

The code in question looks like this, if it adds context:

HorizontalPager(state = pagerState, dragEnabled = dragEnabled) { page ->
    val timeInSeconds = abs(steps[page % steps.size] / 1000L)
    val minutes = (timeInSeconds / 60).toString().padStart(2, '0')
    val seconds = (timeInSeconds % 60).toString().padStart(2, '0')

    Text(
        modifier = Modifier.fillMaxWidth(0.85f),
        text = stringResource(R.string.pomodoro_active_notification_content_body, minutes, seconds),
        textAlign = TextAlign.Center,
        fontSize = LocalDimens.current.intervalTimeFontSize,
        style = MaterialTheme.typography.h1
    )
}
4 Answers

As @CommonsWare correctly pointed out, you need to reverse scaling.

You can get fontScale from LocalDensity:

fontSize = with(LocalDensity.current) {
    (LocalDimens.current.intervalTimeFontSize / fontScale).sp
},
val textStyle = MaterialTheme.typography.h1

val fontSizeDp = with(LocalDensity.current) { textStyle.fontSize.value.dp.toSp() }
Text(
    ...
    style = textStyle,
    fontSize = fontSizeDp,
)

This is an extension function for Int but you can do it for Float if you wish to

@Composable
fun Int.scaledSp(): TextUnit {
    val value: Int = this
    return with(LocalDensity.current) {
        val fontScale = this.fontScale
        val textSize =  value / fontScale
        textSize.sp
  }

We can use CompositionLocalProvider to override the default font scale:

@Composable
fun TextWithFixedSize(
    text: String,
    fontSize: TextUnit,
) {
    val newDensity = Density(
        LocalDensity.current.density,
        fontScale = 2f,
    )
    CompositionLocalProvider(
        LocalDensity provides newDensity,
    ) {
        Text(
            text = text,
            fontSize = fontSize,
        )
    }
}

If you want to use a fixed text size on all the pages of your app, just wrap your root composable with the CompositionLocalProvider.

The same app with different font size settings:

![![enter image description here

Related