admin管理员组

文章数量:1245088

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() ?

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() ?

Share Improve this question asked Feb 16 at 22:06 Ralf WickumRalf Wickum 3,28411 gold badges65 silver badges123 bronze badges 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. – CommonsWare 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. – Ralf Wickum Commented Feb 16 at 22:39
Add a comment  | 

1 Answer 1

Reset to default 0

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/KatieBarnett/Experiments/blob/main/jc-text/src/main/java/dev/katiebarnett/experiments/jctext/components/NonResizingText.kt)

import androidxpose.foundation.layout.Box
import androidxpose.foundation.layout.width
import androidxpose.material3.Text
import androidxpose.runtime.Composable
import androidxpose.ui.Modifier
import androidxpose.ui.platform.LocalDensity
import androidxpose.ui.tooling.preview.Preview
import androidxpose.ui.unit.TextUnit
import androidxpose.ui.unit.dp
import androidxpose.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}")
    }
}


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 
}

本文标签: androidHow can I restrict font size scaling with Jetpack composeStack Overflow