0

Trying to understand how to limit font scaling, from this example here:

Text(
  text = "This is resizing text with font scale ${LocalDensity.current.fontScale}",
  fontSize = 20.sp
)

On Android I can set a systemwide font scaling in the systems Accessibility settings between 1.0 (=100%) and 2.0 (=200%)..

I try to create a function to limit the scaling:

@Composable
fun Float.limitFontScale(maxScale: Int = 200): TextUnit {
    val fontScale = LocalDensity.current.fontScale
    val fontScaleLimited = fontScale.coerceAtMost(maxScale.toFloat() / 100f)
    val scaledSp = (this * fontScaleLimited).sp
    return scaledSp
}

When the systems setting is set to 2.0 (=200%), I would like to shrink the scaling to 150% anyway. I have in my code:

Text(
  text = "This is resizing text with font scale ${LocalDensity.current.fontScale}",
  fontSize = 20.sp.value.limitFontScale(150)
)

i was hoping that the outcome of Text() composable would be the same for following adb commands in terminal:

adb shell settings put system font_scale 2.00

adb shell settings put system font_scale 1.50

But unfortunately, the visible outcome for 2.00 is visibly bigger. I way hoping that both have the same size on device?!

What is wrong? The calcualtion in limitFontScale() ?

2
  • They use non-linear font scaling, I think, so I do not know that your calculation will be exact in any case. Beyond that, it feels like this * fontScaleLimited should be this / fontScaleLimited, the way Katie has it in her Medium post that you linked to. Commented Feb 16 at 22:24
  • In both calculations the 2.00 text size is bigger than in 1.50 scaling. Whn I enter 'limitFontScale(150)' I was hoping both would have the same size. Commented Feb 16 at 22:39

1 Answer 1

2

I think the problem is in this line

val scaledSp = (this * fontScaleLimited).sp

it should be

val scaledSp = (this.value/fontScale * fontScaleLimited).sp

First you have to get the original value, then scale it up to what you want.

Here is the code I used for testing. You can play with it if you need to further modify your function.

I copied it and modified it from the Katie's GitHub repo (https://github.com/KatieBarnett/Experiments/blob/main/jc-text/src/main/java/dev/katiebarnett/experiments/jctext/components/NonResizingText.kt)

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.width
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp


val standardFontSize = 16.sp
@Composable
fun RegularResizingText(
    textToDisplay: String,
    modifier: Modifier = Modifier
) {
    Text(
        text = textToDisplay,
        fontSize = standardFontSize,
        modifier = modifier
    )
}

val TextUnit.nonScaledSp
    @Composable
    get() = (this.value / LocalDensity.current.fontScale).sp

@Composable
fun TextUnit.limitFontScale(maxScale: Int = 200): TextUnit {
    val fontScale = LocalDensity.current.fontScale
    val fontScaleLimited = fontScale.coerceAtMost(maxScale.toFloat() / 100f)
    val scaledSp = (this.value/fontScale * fontScaleLimited).sp
    return scaledSp
}


@Composable
fun NonResizingTextSp(
    textToDisplay :String,
    modifier: Modifier = Modifier
) {
    Text(
        text = textToDisplay,
        fontSize = standardFontSize.limitFontScale(150),
        modifier = modifier
    )
}

@Preview(
    name = "large font",
    group = "Font scaling",
    fontScale = 1.5f,
    showBackground = true
)
@Preview(
    name = "extra large font",
    group = "Font scaling",
    fontScale = 2f,
    showBackground = true
)
annotation class FontScalePreviews

@FontScalePreviews
@Composable
fun RegularResizingTextPreview() {
    Box(modifier = Modifier.width(500.dp)) {
        RegularResizingText(textToDisplay = "This is regular resizing text with font scale ${LocalDensity.current.fontScale}")
    }
}

@FontScalePreviews
@Composable
fun NonResizingTextSpPreview() {
    Box(modifier = Modifier.width(500.dp)) {
        NonResizingTextSp(textToDisplay = "This is non-resizing text with font scale ${LocalDensity.current.fontScale}")
    }
}

enter image description here


Another option is to wrap the Text composable, or all you layout with

CompositionLocalProvider(
        LocalDensity provides Density(
            LocalDensity.current.density,
            1f // - we set here default font scale instead of system one
        )
    ){
// your code here 
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.