Reputation: 749
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.
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
)
}
Upvotes: 24
Views: 14143
Reputation: 126
Below is a sample, of how I am handling it in my code. Restricting font scale to not exceed the upper limit, in this case, 1.15f.
CompositionLocalProvider(
LocalDensity provides Density(
density = LocalDensity.current.density,
fontScale = LocalDensity.current.fontScale.coerceIn(1f, 1.15f)
)
) {
// COMPOSABLE FUNCTION CALL
}
Upvotes: 1
Reputation: 408
Its pretty easy actually. You can just set new CompositionLocalProvider
like this
CompositionLocalProvider(
LocalDensity provides Density(
LocalDensity.current.density,
1f // - we set here default font scale instead of system one
)
) {
//your composables that will use no-scale
}
And please remember that text scaling exists for a purpose. Don't just wrap you whole application in this composition local. Accessibility is really important
You can check max scale for your element to work correctly and than write something like:
val myFontScale = LocalDensity.current.fontScale.coerceIn(0.75f, 1.5f)
And then simply pass this value CompositionLocal
instead of 1f
Upvotes: 15
Reputation: 45
You can use TextUnitType.Unspecified
to ignore system scale:
Text(
text = "text",
color = Color.White,
fontSize = TextUnit(18f, TextUnitType.Unspecified),
)
Upvotes: 0
Reputation: 87605
As @CommonsWare correctly pointed out, you need to reverse scaling.
You can get fontScale
from LocalDensity
:
val Int.nonScaledSp
@Composable
get() = (this / LocalDensity.current.fontScale).sp
Usage:
10.nonScaledSp
An other option is using dp
related text size: it's gonna ignore system Font Size setting, but it's gonna take Display size setting into account - it can be useful in cases when you have some container view size in dp
and wanna text to have size related to the parent parent:
val density = LocalDensity.current
val textSize = with(density) { 15.dp.toSp() }
Upvotes: 43
Reputation: 1345
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:
Upvotes: 3
Reputation: 66526
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
}
Upvotes: 3
Reputation: 124
val textStyle = MaterialTheme.typography.h1
val fontSizeDp = with(LocalDensity.current) { textStyle.fontSize.value.dp.toSp() }
Text(
...
style = textStyle,
fontSize = fontSizeDp,
)
Upvotes: 1