Skip to content

feature: a font family name uses every bundled weight on Android - #120

Open
SRWieZ wants to merge 1 commit into
NativePHP:mainfrom
SRWieZ:feat/android-font-weight-files
Open

SRWieZ wants to merge 1 commit into
NativePHP:mainfrom
SRWieZ:feat/android-font-weight-files

Conversation

@SRWieZ

@SRWieZ SRWieZ commented Oct 3, 2026

Copy link
Copy Markdown
Member

On Android, a custom font only ever comes in one weight.

A font file holds one weight: Nunito-Regular.ttf, Nunito-Bold.ttf, and so on. Today the Android renderer builds a font from a single file, so:

  • font="Nunito-Regular" + font-bold doesn't load Nunito-Bold.ttf. Android fakes the bold by thickening the regular letters, and font-medium / font-semibold look the same as regular or as the fake bold.
  • font="Nunito" (the family name) finds no file called Nunito.ttf, so the text silently falls back to the system font.

iOS doesn't have this problem, so the same Blade looks different on the two platforms.

This PR: when a font name has no file of its own, the Android resolver collects every weight file of that family (Nunito-Regular, -Medium, -SemiBold, -Bold, -ExtraBold, and also Thin/Light/Black when present) into one font. font="Nunito" plus the usual font-* weight classes then use the real cuts, the way the font was designed. Nothing changes for a name that matches a file (font="Nunito-Bold" still loads that file), so existing apps are not affected.

Why it helps everyone: apps that bundle a brand font get proper bold, semibold and medium text on Android, matching iOS, without one font alias per weight. It is also a way around Android phones whose maker replaces the system font and ignores app weights (Xiaomi's HyperOS does this with MiSans): bundle a family once, and the weights work on every phone.

To reproduce, bundle the Nunito weights in resources/fonts/ (Nunito-Regular.ttf, Nunito-Medium.ttf, Nunito-SemiBold.ttf, Nunito-Bold.ttf, Nunito-ExtraBold.ttf):

<native:row class="w-full px-5 pt-6 gap-6">
    @foreach (['Nunito-Regular', 'Nunito'] as $font)
        <native:column class="flex-1 gap-3">
            <native:text class="text-xs">font="{{ $font }}"</native:text>
            @foreach (['normal' => 'Regular', 'medium' => 'Medium', 'semibold' => 'SemiBold', 'bold' => 'Bold', 'extrabold' => 'ExtraBold'] as $class => $label)
                <native:text font="{{ $font }}" class="font-{{ $class }} text-2xl">{{ $label }}</native:text>
            @endforeach
        </native:column>
    @endforeach
</native:row>

Before / after (Android emulator, API 36). Before, the left column fakes every weight from one file and the right column falls back to the system font. After, the right column uses the real Nunito weights:

font weights

A token that names no single file ("Roboto") now picks up every weight
file bundled for it (Roboto-Regular, Roboto-Bold, ...) as one Compose
FontFamily, so font-bold and font-semibold select the real cut instead
of Compose faking bold from one regular file.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant