Implementing Font Scaling Support in Android
Android allows users to change font scale in Settings → Display → Font Size. Range: 0.85x to 2.0x on most stock versions (Samsung One UI allows up to 1.6x via standard UI, but fontScale in Configuration can reach 2.0x). sp units scale; dp do not.
Main Failures
sp vs dp for Text
android:textSize="16sp" — correct, font scales. android:textSize="16dp" — doesn't scale. Hardcoding in dp is one of the most frequent errors, which Lint doesn't always catch (warns but not as Error).
In Compose: fontSize = 16.sp — scales. fontSize = 16.dp — Lint will error starting Compose 1.3. But TextUnit.Unspecified in custom components — problem again.
Fixed Container Height
Most common issue: android:layout_height="48dp" on TextView or container with text. At fontScale = 2.0, 16sp text occupies ~64dp height. 48dp container — clipping.
Correct: wrap_content for height of all text elements. For ConstraintLayout — remove fixed height from chains with text.
minHeight can stay for touch target (48dp minimum per Material Design) — but only via minHeight, not height.
Strings with Substitutions
String.format("You earned %d points", points) — with long number string gets longer. But problem isn't the number, it's fixed layout around it. ConstraintLayout with wrap_content handles it; nested LinearLayout with gravity — doesn't.
Compose: LocalDensity and Scale
In Jetpack Compose LocalDensity contains both density (DPI) and fontScale. If you manually convert sizes via density.density without accounting for fontScale — custom components with TextUnit calculations don't scale.
with(LocalDensity.current) { 16.sp.toPx() } — returns pixels already accounting for fontScale. If you use this as Canvas height — fine. If you ignore result and set fixed height in Modifier — no.
Non-typical Case: Disabling Scaling for Specific Elements
Sometimes design requires specific element (logo with text, decorative label) not to scale. In Compose: CompositionLocalProvider(LocalDensity provides Density(density = LocalDensity.current.density, fontScale = 1f)) — overrides fontScale to 1.0 inside subtree. Acceptable for decorative elements, not for functional text.
In XML: android:textSize="16dp" — technically works, but Lint complains. Better wrap in style with NonScalable suffix to make it explicit.
Testing
adb shell settings put system font_scale 2.0 — instantly changes scale without device restart. After checking: adb shell settings put system font_scale 1.0.
Android Studio Device Emulator: Pixel 6 with fontScale 2.0 — first bench for layout checking. Real Samsung with One UI — second bench, behavior differs there.
Espresso snapshot-tests with InstrumentationRegistry.getInstrumentation().targetContext.resources.configuration.fontScale = 2f — for regression control.
Timeframe: 2-3 days. Cost calculated individually.







