I am writing a suite of apps. Some will be multiplatform, using Compose Multiplatform for the UI. One will be only deployed on Android.
I defined the design system using Compose Multiplatform and Compose Resources. This includes a custom font, in commonMain/composeResources/font/
of my design system module:
This works well, even from a regular Android project. However, that Android project also uses a third-party library, where I need to use the same custom font. That library uses the legacy View
system, so I have a second copy of my custom font in res/font/
of the module that needs it.
Everything runs and looks correct, but the result is that I have two copies of this font. The font is over 800KB, and ideally I would only have one copy.
Is there a way that I can use a font defined in Compose Resources with a View
?
Right now, I am using the Android font resource in a style, via <item name="android:fontFamily">@font/inter_variable</item>
. Probably I can switch that to configuring the font in Kotlin. So, for example, if there is a way I can get a Typeface
for the Compose Resources font, I may be able to use that with setTypeface()
on a TextView.
Using Nima's answer as inspiration, I wound up with:
@OptIn(ExperimentalResourceApi::class)
public fun createTypefaceFromComposeResource(context: Context, fontFileName: String): Typeface? = Typeface.createFromAsset(
context.assets,
Uri.parse(Res.getUri("font/$fontFileName")).path?.replace("/android_asset/", "")
)
Usage would be something like:
myTextView.typeface = createTypefaceFromComposeResource(context, "myAwesomeFont.ttf")
Res.getUri()
returns a string representation of an Android asset Uri
: file:///android_asset/path/to/the/resource
. Right now I'm playing it safe, parsing the Uri
and using path
to get rid of the scheme. Unfortunately, the android_asset
segment is considered to be part of the path, which is why I remove it using replace()
. If you wanted, you could skip the Uri.parse()
and use replace()
for the whole initial segment.