Vince
Vince

Reputation: 3084

Using fonts in a Compose Multiplatform project

I am looking for a way to easily use custom fonts in a Compose Multiplatform project.

I found that we need to use Font from the androidx.compose.ui.text.platform.Font package. But this object takes in parameter data: ByteArray.

Until now, I haven't found a way to use Font to import a font file from the commonMain resource directory.

How to use custom fonts in the commonMain part of a Compose Multiplatform project?

Thank you for your help!

Upvotes: 5

Views: 6020

Answers (4)

Quốc Hùng
Quốc Hùng

Reputation: 451

They adopted font for compose resource feature, you can add your font to font resources folder

Font resource

and then apply font to your text style like so

val Typography1  
    @Composable // Composable is required for loading font from compose resources
    get() = Typography(
        displayLarge = TextStyle(
            fontFamily = FontFamily(Font(Res.font.itim_regular)) 
        )
    )

// Or you can also apply font to all styles
val Typography
    @Composable
    get() = Typography().let {
        val itimFont = FontFamily(Font(Res.font.itim_regular))
        it.copy(
            displayLarge = it.displayLarge.copy(fontFamily = itimFont),
            displayMedium = it.displayMedium.copy(fontFamily = itimFont),
            displaySmall = it.displaySmall.copy(fontFamily = itimFont),
            headlineLarge = it.headlineLarge.copy(fontFamily = itimFont),
            headlineMedium = it.headlineMedium.copy(fontFamily = itimFont),
            headlineSmall = it.headlineSmall.copy(fontFamily = itimFont),
            titleLarge = it.titleLarge.copy(fontFamily = itimFont),
            titleMedium = it.titleMedium.copy(fontFamily = itimFont),
            titleSmall = it.titleSmall.copy(fontFamily = itimFont),
            bodyLarge = it.bodyLarge.copy(fontFamily = itimFont),
            bodyMedium = it.bodyMedium.copy(fontFamily = itimFont),
            bodySmall = it.bodySmall.copy(fontFamily = itimFont),
            labelLarge = it.labelLarge.copy(fontFamily = itimFont),
            labelMedium = it.labelMedium.copy(fontFamily = itimFont),
            labelSmall = it.labelSmall.copy(fontFamily = itimFont)
        )
    }

Upvotes: 1

Shahriar Zaman
Shahriar Zaman

Reputation: 938

There is a easy way to use common resources directory for both android and desktop.

create src/commonMain/resources/ directory inside :shared module. then set the android source sets of android and jvm as follows:

kotlin {
    targetHierarchy.default()

    android {
        compilations.all {
            kotlinOptions {
                jvmTarget = "1.8"
            }
        }
    }

    jvm {
        sourceSets {
            named("jvmMain") {
                resources.srcDir("src/commonMain/resources") // <============= here
            }
        }
    }

    sourceSets {
        val commonMain by getting {
            dependencies {
                // compose libraries
                implementation(compose.runtime)
                implementation(compose.foundation)
                @OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class)
                implementation(compose.components.resources)
            }
        }
        
        val jvmMain by getting {
            dependencies {
                implementation(compose.desktop.currentOs)
            }
        }
    }
}

android {
    namespace = "a.b.c"
    compileSdk = 33
    defaultConfig {
        minSdk = 21
    }
    sourceSets {
        named("main") {
            manifest.srcFile("src/androidMain/AndroidManifest.xml")
            res.srcDirs("src/commonMain/resources") // <============= here
        }
    }
}

To get the fonts create a provider file inside :shared:commonMain/ as:

expect val acmeTypography: Typography

Now implement it inside both :shared:androidMain and :shared:jvmMain as:

// shared:jvmMain/

import androidx.compose.ui.text.platform.Font

actual val acmeTypography = Typography(
    defaultFontFamily = FontFamily(
        Font(resource = "font/acme_regular.ttf", FontWeight.Normal)
    ),
)

// shared:androidMain
import androidx.compose.ui.text.font.Font

actual val acmeTypography = Typography(
    defaultFontFamily = FontFamily(
        Font(R.font.acme_regular, FontWeight.Normal)
    ),
)

Upvotes: 5

Jassiel Melgoza
Jassiel Melgoza

Reputation: 21

This is other way to link and use custom Compose fonts in Compose Multiplatform

https://jassielcastro.medium.com/custom-fonts-in-android-and-ios-applications-using-kotlin-multiplatform-and-jetpack-compose-c88d2d519e77

Upvotes: 2

Louis Duboscq
Louis Duboscq

Reputation: 497

The easiest way is to use moko resources : https://github.com/icerockdev/moko-resources

Add the font in commonMain/resources/MR/fonts

for example: PlayfairDisplay-Bold.ttf file

Then load the FontFamily :

val fontFamilyExtraBold: FontFamily = fontFamilyResource(SharedRes.fonts.PlayfairDisplay.extraBold)

And finaly use it in your Typography in your theme. More infos on Moko resources docs.

Upvotes: 3

Related Questions