Praca z czcionkami

Na tej stronie dowiesz się, jak ustawić czcionki w aplikacji Compose.

Ustaw czcionkę

Text ma parametr fontFamily, który umożliwia ustawienie czcionki używanej w funkcji kompozycyjnej. Domyślnie uwzględniane są rodziny czcionek szeryfowych, bezszeryfowych, o stałej szerokości znaków i kursywy:

@Composable
fun DifferentFonts() {
    Column {
        Text("Hello World", fontFamily = FontFamily.Serif)
        Text("Hello World", fontFamily = FontFamily.SansSerif)
    }
}

słowa,

Możesz użyć atrybutu fontFamily, aby pracować z niestandardowymi czcionkami i krojami pisma zdefiniowanymi w folderze res/font:

Graficzne przedstawienie folderu res > font w środowisku programistycznym

Ten przykład pokazuje, jak zdefiniować fontFamily na podstawie tych plików czcionek i za pomocą funkcji Font:

val firaSansFamily = FontFamily(
    Font(R.font.firasans_light, FontWeight.Light),
    Font(R.font.firasans_regular, FontWeight.Normal),
    Font(R.font.firasans_italic, FontWeight.Normal, FontStyle.Italic),
    Font(R.font.firasans_medium, FontWeight.Medium),
    Font(R.font.firasans_bold, FontWeight.Bold)
)

Możesz przekazać ten obiekt fontFamily do funkcji kompozycyjnej Text. Ponieważ fontFamily może zawierać różne grubości, możesz ręcznie ustawić fontWeight, aby wybrać odpowiednią grubość tekstu:

Column {
    Text(text = "text", fontFamily = firaSansFamily, fontWeight = FontWeight.Light)
    Text(text = "text", fontFamily = firaSansFamily, fontWeight = FontWeight.Normal)
    Text(
        text = "text",
        fontFamily = firaSansFamily,
        fontWeight = FontWeight.Normal,
        fontStyle = FontStyle.Italic
    )
    Text(text = "text", fontFamily = firaSansFamily, fontWeight = FontWeight.Medium)
    Text(text = "text", fontFamily = firaSansFamily, fontWeight = FontWeight.Bold)
}

słowa,

Aby dowiedzieć się, jak ustawić typografię w całej aplikacji, zapoznaj się z artykułem Niestandardowe systemy projektowania w Compose.

Czcionki do pobrania

Od wersji Compose 1.2.0 możesz używać interfejsu Downloadable Fonts API w aplikacji Compose, aby asynchronicznie pobierać czcionki Google i używać ich w aplikacji.

Obsługa czcionek do pobrania dostarczanych przez niestandardowych dostawców nie jest obecnie dostępna.

Używanie czcionek do pobrania w kodzie

Aby pobrać czcionkę automatycznie z poziomu aplikacji, wykonaj te czynności:

  1. Dodaj zależność:

    Dynamiczny

    dependencies {
        ...
        implementation "androidx.compose.ui:ui-text-google-fonts:1.12.1"
    }

    Kotlin

    dependencies {
        ...
        implementation("androidx.compose.ui:ui-text-google-fonts:1.12.1")
    }
  2. Zainicjuj GoogleFont.Provider za pomocą danych logowania do Google Fonts:
    val provider = GoogleFont.Provider(
        providerAuthority = "com.google.android.gms.fonts",
        providerPackage = "com.google.android.gms",
        certificates = R.array.com_google_android_gms_fonts_certs
    )
    Dostawca otrzymuje te parametry:
    • Urząd dostawcy czcionek Google Fonts.
    • Pakiet dostawcy czcionek do weryfikacji tożsamości dostawcy.
    • Lista zestawów skrótów certyfikatów służących do weryfikacji tożsamości dostawcy. Skróty wymagane przez dostawcę Google Fonts znajdziesz w pliku font_certs.xml w przykładowej aplikacji Jetchat.
  3. Zdefiniuj FontFamily:
    // ...
     import androidx.compose.ui.text.googlefonts.GoogleFont
     import androidx.compose.ui.text.font.FontFamily
     import androidx.compose.ui.text.googlefonts.Font
     // ...
    
    val fontName = GoogleFont("Lobster Two")
    
    val fontFamily = FontFamily(
        Font(googleFont = fontName, fontProvider = provider)
    )
    Możesz wysłać zapytanie o inne parametry czcionki, takie jak grubość i styl, używając odpowiednio FontWeight i FontStyle:
    // ...
     import androidx.compose.ui.text.googlefonts.GoogleFont
     import androidx.compose.ui.text.font.FontFamily
     import androidx.compose.ui.text.googlefonts.Font
     // ...
    
    val fontName = GoogleFont("Lobster Two")
    
    val fontFamily = FontFamily(
        Font(
            googleFont = fontName,
            fontProvider = provider,
            weight = FontWeight.Bold,
            style = FontStyle.Italic
        )
    )
  4. Skonfiguruj FontFamily do użycia w funkcji typu „composable” Text:

Text(
    fontFamily = fontFamily, text = "Hello World!"
)

Możesz też zdefiniować typografię, aby używać FontFamily:

val MyTypography = Typography(
    bodyMedium = TextStyle(
        fontFamily = fontFamily, fontWeight = FontWeight.Normal, fontSize = 12.sp/*...*/
    ),
    bodyLarge = TextStyle(
        fontFamily = fontFamily,
        fontWeight = FontWeight.Bold,
        letterSpacing = 2.sp,
        /*...*/
    ),
    headlineMedium = TextStyle(
        fontFamily = fontFamily, fontWeight = FontWeight.SemiBold/*...*/
    ),
    /*...*/
)

Następnie ustaw typografię na motyw aplikacji:

MyAppTheme(
    typography = MyTypography
)/*...*/

Przykładową aplikację, która implementuje czcionki do pobrania w Compose razem z Material3, znajdziesz w Jetchat.

Dodawanie czcionek zastępczych

Możesz określić łańcuch czcionek zastępczych na wypadek, gdyby czcionka nie została prawidłowo pobrana. Jeśli na przykład czcionka do pobrania jest zdefiniowana w ten sposób:

// ...
 import androidx.compose.ui.text.googlefonts.Font
 // ...

val fontName = GoogleFont("Lobster Two")

val fontFamily = FontFamily(
    Font(googleFont = fontName, fontProvider = provider),
    Font(googleFont = fontName, fontProvider = provider, weight = FontWeight.Bold)
)

Możesz zdefiniować domyślne ustawienia czcionki dla obu grubości w ten sposób:

// ...
 import androidx.compose.ui.text.font.Font
 import androidx.compose.ui.text.googlefonts.Font
 // ...

val fontName = GoogleFont("Lobster Two")

val fontFamily = FontFamily(
    Font(googleFont = fontName, fontProvider = provider),
    Font(resId = R.font.my_font_regular),
    Font(googleFont = fontName, fontProvider = provider, weight = FontWeight.Bold),
    Font(resId = R.font.my_font_regular_bold, weight = FontWeight.Bold)
)

Upewnij się, że dodajesz prawidłowe importy.

Zdefiniowanie FontFamily w ten sposób tworzy FontFamily zawierający 2 łańcuchy, po jednym na każdą wagę. Mechanizm wczytywania najpierw spróbuje znaleźć czcionkę online, a następnie czcionkę znajdującą się w lokalnym folderze zasobów R.font.

Debugowanie implementacji

Aby sprawdzić, czy czcionka jest pobierana prawidłowo, możesz zdefiniować moduł obsługi współprogramu debugowania. Twój moduł obsługi określa, co należy zrobić, jeśli czcionka nie zostanie załadowana asynchronicznie.

Zacznij od utworzenia CoroutineExceptionHandler:

val handler = CoroutineExceptionHandler { _, throwable ->
    // process the Throwable
    Log.e(TAG, "There has been an issue: ", throwable)
}

Przekaż go do metody createFontFamilyResolver, aby moduł rozpoznawania nazw używał nowego modułu obsługi:

CompositionLocalProvider(
    LocalFontFamilyResolver provides createFontFamilyResolver(LocalContext.current, handler)
) {
    Column {
        Text(
            text = "Hello World!", style = MaterialTheme.typography.bodyMedium
        )
    }
}

Możesz też użyć interfejsu API isAvailableOnDevice dostawcy, aby sprawdzić, czy dostawca jest dostępny i czy certyfikaty są prawidłowo skonfigurowane. W tym celu możesz wywołać metodę isAvailableOnDevice, która zwraca wartość false, jeśli dostawca jest nieprawidłowo skonfigurowany.

val context = LocalContext.current
LaunchedEffect(Unit) {
    if (provider.isAvailableOnDevice(context)) {
        Log.d(TAG, "Success!")
    }
}

Uwagi

Udostępnienie nowych czcionek na Androidzie zajmuje Google Fonts kilka miesięcy. Istnieje odstęp czasowy między dodaniem czcionki na stronie fonts.google.com a jej udostępnieniem przez interfejs API czcionek do pobrania (w systemie View lub w Compose). Nowo dodane czcionki mogą nie zostać wczytane w aplikacji i może pojawić się błąd IllegalStateException. Aby pomóc deweloperom odróżnić ten błąd od innych typów błędów wczytywania czcionek, dodaliśmy opis wyjątku w Compose z tymi zmianami. Jeśli znajdziesz jakieś problemy, zgłoś je za pomocą narzędzia Issue Tracker.

Używanie czcionek zmiennych

Czcionka zmienna to format czcionki, który umożliwia umieszczenie różnych stylów w jednym pliku czcionki. W przypadku czcionek zmiennych możesz modyfikować osie (lub parametry), aby wygenerować preferowany styl. Te osie mogą być standardowe, np. grubość, szerokość, pochylenie i kursywa, lub niestandardowe, które różnią się w zależności od czcionki zmiennej.

5 konfiguracji tej samej czcionki zmiennej z różnymi wartościami osi.
Rysunek 1. Tekst z tą samą czcionką zmienną dostosowaną za pomocą różnych wartości osi.

Używanie czcionek zmiennych zamiast zwykłych plików czcionek pozwala mieć tylko jeden plik czcionki zamiast kilku.

Więcej informacji o czcionkach zmiennych znajdziesz w Google Fonts Knowledge, całym katalogu dostępnych czcionek zmiennych oraz tabeli obsługiwanych osi dla każdej czcionki.

Z tego dokumentu dowiesz się, jak zaimplementować czcionkę zmienną w aplikacji Compose.

Wczytywanie czcionki zmiennej

  1. Pobierz czcionkę zmienną, której chcesz użyć (np. Roboto Flex), i umieść ją w folderze app/res/font w aplikacji. Upewnij się, że plik .ttfDodany plik to wersja czcionki zmiennej, a nazwa pliku czcionki jest zapisana małymi literami i nie zawiera znaków specjalnych.

  2. Aby wczytać czcionkę zmienną, zdefiniuj FontFamily, używając czcionki umieszczonej w katalogu res/font/:

    // In Typography.kt
    @OptIn(ExperimentalTextApi::class)
    val displayLargeFontFamily =
        FontFamily(
            Font(
                R.font.robotoflex_variable,
                variationSettings = FontVariation.Settings(
                    FontVariation.weight(950),
                    FontVariation.width(30f),
                    FontVariation.slant(-6f),
                )
            )
        )

    Interfejs FontVariation API umożliwia konfigurowanie standardowych osi czcionek, takich jak grubość, szerokość i pochylenie. Są to standardowe osie, które są dostępne w przypadku każdej czcionki zmiennej. Możesz utworzyć różne konfiguracje czcionki w zależności od tego, gdzie będzie używana.

  3. Czcionki zmienne są dostępne tylko w Androidzie w wersji O lub nowszej, więc dodaj zabezpieczenie i skonfiguruj odpowiednią czcionkę zastępczą:

    // In Typography.kt
    val default = FontFamily(
        /*
        * This can be any font that makes sense
        */
        Font(
            R.font.robotoflex_static_regular
        )
    )
    @OptIn(ExperimentalTextApi::class)
    val displayLargeFontFamily = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        FontFamily(
            Font(
                R.font.robotoflex_variable,
                variationSettings = FontVariation.Settings(
                    FontVariation.weight(950),
                    FontVariation.width(30f),
                    FontVariation.slant(-6f),
                )
            )
        )
    } else {
        default
    }

  4. Wyodrębnij ustawienia do zestawu stałych, aby ułatwić ich ponowne użycie, i zastąp ustawienia czcionki tymi stałymi:

    // VariableFontDimension.kt
    object DisplayLargeVFConfig {
        const val WEIGHT = 950
        const val WIDTH = 30f
        const val SLANT = -6f
        const val ASCENDER_HEIGHT = 800f
        const val COUNTER_WIDTH = 500
    }
    
    @OptIn(ExperimentalTextApi::class)
    val displayLargeFontFamily = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        FontFamily(
            Font(
                R.font.robotoflex_variable,
                variationSettings = FontVariation.Settings(
                    FontVariation.weight(DisplayLargeVFConfig.WEIGHT),
                    FontVariation.width(DisplayLargeVFConfig.WIDTH),
                    FontVariation.slant(DisplayLargeVFConfig.SLANT),
                )
            )
        )
    } else {
        default
    }

  5. Skonfiguruj typografię Material Design 3, aby używać FontFamily:

    // Type.kt
    val Typography = Typography(
        displayLarge = TextStyle(
            fontFamily = displayLargeFontFamily,
            fontSize = 50.sp,
            lineHeight = 64.sp,
            letterSpacing = 0.sp,
            /***/
        )
    )

    W tym przykładzie użyto displayLarge typografii Material 3, która ma inne domyślne ustawienia czcionki i zalecane zastosowania. Na przykład displayLarge należy używać w przypadku krótkiego, ważnego tekstu, ponieważ jest to największy tekst na ekranie.

    W Material 3 możesz zmienić domyślne wartości TextStyle i fontFamily, aby dostosować typografię. We fragmencie kodu powyżej skonfigurujesz instancje TextStyle, aby dostosować ustawienia czcionki dla każdej rodziny czcionek.

  6. Po zdefiniowaniu typografii przekaż ją do M3 MaterialTheme:

    MaterialTheme(
        colorScheme = MaterialTheme.colorScheme,
        typography = Typography,
        content = content
    )

  7. Na koniec użyj funkcji kompozycyjnej Text i określ styl jako jeden ze zdefiniowanych stylów typografii, MaterialTheme.typography.displayLarge:

    @Composable
    @Preview
    fun CardDetails() {
        MyCustomTheme {
            Card(
                shape = RoundedCornerShape(8.dp),
                elevation = CardDefaults.cardElevation(defaultElevation = 4.dp),
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(16.dp)
            ) {
                Column(
                    modifier = Modifier.padding(16.dp)
                ) {
                    Text(
                        text = "Compose",
                        style = MaterialTheme.typography.displayLarge,
                        modifier = Modifier.padding(bottom = 8.dp),
                        maxLines = 1
                    )
                    Text(
                        text = "Beautiful UIs on Android",
                        style = MaterialTheme.typography.headlineMedium,
                        modifier = Modifier.padding(bottom = 8.dp),
                        maxLines = 2
                    )
                    Text(
                        text = "Jetpack Compose is Android’s recommended modern toolkit for building native UI. It simplifies and accelerates UI development on Android. Quickly bring your app to life with less code, powerful tools, and intuitive Kotlin APIs.",
                        style = MaterialTheme.typography.bodyLarge,
                        modifier = Modifier.padding(bottom = 8.dp),
                        maxLines = 3
                    )
                }
            }
        }
    }

    Każdy element kompozycyjny Text jest konfigurowany za pomocą stylu Material Theming i zawiera inną konfigurację czcionki zmiennej. Możesz użyć MaterialTheme.typography, aby pobrać typografię dostarczoną do funkcji kompozycyjnej MaterialTheme M3.

3 różne teksty, każdy z inną konfiguracją czcionki.
Rysunek 2. Czcionka zmienna zastosowana w 3 różnych konfiguracjach.

Używanie osi niestandardowych

Czcionki mogą też mieć osie niestandardowe. Są one zdefiniowane w samym pliku czcionki. Na przykład czcionka Roboto Flex ma oś wysokości wydłużenia górnego ("YTAS"), która dostosowuje wysokość wydłużeń górnych małych liter, a szerokość wewnętrznego światła ("XTRA") dostosowuje szerokość każdej litery.

Wartość tych osi możesz zmienić w ustawieniach FontVariation.

Więcej informacji o osiach niestandardowych, które możesz skonfigurować dla czcionki, znajdziesz w tabeli obsługiwanych osi dla każdej czcionki.

  1. Aby używać osi niestandardowych, zdefiniuj funkcje dla niestandardowych osi ascenderHeight i counterWidth:

    fun ascenderHeight(ascenderHeight: Float): FontVariation.Setting {
        require(ascenderHeight in 649f..854f) { "'Ascender Height' must be in 649f..854f" }
        return FontVariation.Setting("YTAS", ascenderHeight)
    }
    
    fun counterWidth(counterWidth: Int): FontVariation.Setting {
        require(counterWidth in 323..603) { "'Counter width' must be in 323..603" }
        return FontVariation.Setting("XTRA", counterWidth.toFloat())
    }

    Te funkcje wykonują następujące czynności:

    • Zdefiniuj ograniczenia dotyczące wartości, które mogą akceptować. Jak widać w katalogu czcionek zmiennych, ascenderHeight (YTAS) ma wartość minimalną 649f i maksymalną 854f.
    • Zwróć ustawienie czcionki, aby konfiguracja była gotowa do dodania do czcionki. W metodzie FontVariation.Setting() nazwa osi (YTAS, XTRA) jest zakodowana na stałe i przyjmuje wartość jako parametr.
  2. Używając osi z konfiguracją czcionki, przekaż dodatkowe parametry do każdego wczytywanego elementu Font:

    @OptIn(ExperimentalTextApi::class)
    val displayLargeFontFamily = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        FontFamily(
            Font(
                R.font.robotoflex_variable,
                variationSettings = FontVariation.Settings(
                    FontVariation.weight(DisplayLargeVFConfig.WEIGHT),
                    FontVariation.width(DisplayLargeVFConfig.WIDTH),
                    FontVariation.slant(DisplayLargeVFConfig.SLANT),
                    ascenderHeight(DisplayLargeVFConfig.ASCENDER_HEIGHT),
                    counterWidth(DisplayLargeVFConfig.COUNTER_WIDTH)
                )
            )
        )
    } else {
        default
    }

    Zauważ, że wysokość wydłużeń górnych małych liter jest teraz większa, a pozostały tekst jest szerszy:

3 różne teksty pokazujące różne konfiguracje czcionek zmiennych z ustawionymi niestandardowymi osiami – niektóre mają wyższe wydłużenia górne i są szersze niż wcześniej.
Rysunek 3. Tekst pokazujący niestandardowe osie ustawione w czcionkach zmiennych.

Dodatkowe materiały

Więcej informacji znajdziesz w tym poście na blogu o czcionkach zmiennych: