Praca z czcionkami

Na tej stronie dowiesz się, jak ustawić czcionki w aplikacji Utwórz.

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 i kursywnej:

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

Słowa

Możesz użyć atrybutu fontFamily do pracy z niestandardowymi czcionkami i krojami czcionek zdefiniowanych w folderze res/font:

Graficzne przedstawienie folderu res > czcionek w środowisku programistycznym

Ten przykład pokazuje, jak można zdefiniować element fontFamily na podstawie tych plików czcionek i użyć 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 element (fontFamily) do funkcji kompozycyjnej Text. fontFamily może obejmować różne wagi, więc możesz ręcznie ustawić fontWeight, aby wybrać odpowiednią wagę dla 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

Więcej informacji o ustawianiu typografii w całej aplikacji znajdziesz w artykule Niestandardowe systemy projektowania w usłudze Compose.

Czcionki do pobrania

Od wersji Compose 1.2.0 możesz używać dostępnego do pobrania interfejsu API czcionek w aplikacji Compose, aby asynchronicznie pobierać czcionki Google i używać ich w aplikacji.

Czcionki do pobrania dostarczane przez dostawców niestandardowych nie są obecnie obsługiwane.

Automatyczne korzystanie z czcionek, które można pobrać

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

  1. Dodaj zależność:

    Odlotowe

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

    Kotlin

    dependencies {
        ...
        implementation("androidx.compose.ui:ui-text-google-fonts:1.6.8")
    }
  2. Zainicjuj GoogleFont.Provider za pomocą danych logowania 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
    )
    Parametry, które otrzymuje dostawca to:
    • Urząd dostawcy czcionek Google Fonts.
    • Pakiet dostawcy czcionek do weryfikacji tożsamości dostawcy.
    • Lista zestawów haszy certyfikatów w celu weryfikacji tożsamości dostawcy. Hashe wymagane przez dostawcę Google Fonts znajdziesz w pliku font_certs.xml w przykładowej aplikacji Jetchat.
  3. Zdefiniuj parametr 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 wysyłać zapytania o inne parametry czcionki, takie jak waga 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 obiekt FontFamily do użycia w funkcji tworzenia tekstu:

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

Możesz też określić typografię, aby użyć właściwości FontFamily:

val MyTypography = Typography(
    labelMedium = TextStyle(
        fontFamily = fontFamily, fontWeight = FontWeight.Normal, fontSize = 12.sp/*...*/
    ),
    labelLarge = TextStyle(
        fontFamily = fontFamily,
        fontWeight = FontWeight.Bold,
        letterSpacing = 2.sp,
        /*...*/
    ),
    displayMedium = TextStyle(
        fontFamily = fontFamily, fontWeight = FontWeight.SemiBold/*...*/
    ),
    /*...*/
)

Następnie ustaw typografię na motyw aplikacji:

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

Przykład aplikacji, która w funkcji Compose oprócz Material3 implementuje czcionki do pobrania, znajdziesz w przykładowej aplikacji Jetchat.

Dodawanie czcionek zastępczych

Możesz określić łańcuch wartości zastępczych czcionki, jeśli czcionka nie zostanie prawidłowo pobrana. Jeśli na przykład masz zdefiniowaną czcionkę do pobrania 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 w ten sposób zdefiniować wartości domyślne czcionki dla obu tych grubości:

// ...
 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)
)

Sprawdź, czy importujesz właściwe dane.

Zdefiniowanie w ten sposób FontFamily powoduje utworzenie elementu FontFamily zawierającego 2 łańcuchy, po jednym na wagę. Mechanizm wczytywania najpierw spróbuje rozpoznać czcionkę online, a potem czcionkę z lokalnego folderu zasobów R.font.

Debugowanie implementacji

Aby sprawdzić, czy czcionka jest pobierana prawidłowo, możesz zdefiniować moduł obsługi współrzędu debugowania. Nick zawiera informacje o czynnościach, które należy wykonać w przypadku, gdy czcionka nie załaduje się 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, by resolver 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 od dostawcy, aby sprawdzić, czy dostawca jest dostępny, a certyfikaty są prawidłowo skonfigurowane. Aby to zrobić, możesz wywołać metodę isAvailableOnDevice, która zwraca wartość fałsz, jeśli dostawca jest nieprawidłowo skonfigurowany.

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

Uwagi

Google Fonts ma kilka miesięcy, by udostępnić nowe czcionki na Androida. Od chwili dodania czcionki na stronie fonts.google.com a udostępnieniem jej przez interfejs API czcionek do pobrania (w systemie wyświetlania lub w narzędziu Compose) jest przerwa. Nowo dodane czcionki mogą nie załadować się w aplikacji z parametrem IllegalStateException. Aby ułatwić deweloperom rozpoznawanie tego błędu wśród innych typów błędów wczytywania czcionek, dodaliśmy w funkcji tworzenia wiadomości opisowe komunikaty dotyczące wyjątku w narzędziu Compose ze zmianami, które opisaliśmy tutaj. Jeśli znajdziesz jakieś problemy, zgłoś je za pomocą narzędzia do śledzenia problemów.

Używanie czcionek zmiennych

Czcionka zmiennej to format czcionki, który pozwala na zapisanie różnych stylów w jednym pliku czcionki. Dzięki zmiennym czcionkom możesz modyfikować osie (lub parametry), by generować preferowany styl. Osie te mogą być standardowe (np. waga, szerokość, pochylenie i kursywa) lub niestandardowe, które różnią się w zależności od czcionek zmiennej.

Pięć konfiguracji tej samej czcionki zmiennej z różnymi wartościami na osi.
Rysunek 1. Tekst korzystający z tej samej czcionki zmiennej, dostosowany za pomocą różnych wartości osi.

Użycie czcionek zmiennych zamiast zwykłych plików czcionek sprawia, że możesz mieć tylko jeden plik czcionek zamiast kilku.

Więcej informacji o czcionkach zmiennych znajdziesz w Centrum wiedzy na temat czcionek Google, w całym katalogu dostępnych czcionek zmiennych i w tabeli obsługiwanych osi dla każdej czcionki.

Ten dokument pokazuje, jak wdrożyć czcionkę zmiennej w aplikacji Compose.

Wczytywanie czcionki zmiennej

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

  2. Aby wczytać czcionkę zmiennej, określ FontFamily za pomocą 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 osie czcionek, takich jak waga, szerokość i nachyl. Są to standardowe osie, które są dostępne ze zmiennymi czcionkami. Możesz tworzyć różne konfiguracje czcionki w zależności od miejsca, w którym czcionka będzie używana.

  3. Czcionki zmiennych są dostępne tylko na urządzeniach z Androidem w wersji O lub nowszej, dlatego musisz dodać barierę i skonfigurować odpowiednią opcję 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 wykorzystanie, 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ę interfejsu Material Design 3, aby korzystać z interfejsu FontFamily:

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

    W tym przykładzie zastosowano typografię Material 3 w języku displayLarge, która ma inne domyślne ustawienia czcionki i zalecane zastosowania. Na przykład displayLarge używaj w przypadku krótkiego, krytycznego tekstu, ponieważ jest to największy tekst na ekranie.

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

  6. Gdy już zdefiniujesz typografię, przekaż ją do MaterialTheme M3:

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

  7. Na koniec użyj funkcji kompozycyjnej Text i określ styl do jednego ze zdefiniowanych stylów typograficznych (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żda funkcja kompozycyjna Text jest konfigurowana za pomocą stylu motywu Material Design i zawiera inną zmienną konfigurację czcionki. Możesz użyć MaterialTheme.typography, aby pobrać typografię udostępnioną funkcji kompozycyjnej M3 MaterialTheme.

Trzy różne teksty o różnych konfiguracjach czcionek.
Rys. 2. Czcionka zmiennej została zastosowana w 3 różnych konfiguracjach.

Użyj niestandardowych osi

Czcionki mogą też mieć niestandardowe osie. Są one zdefiniowane w pliku czcionek. Na przykład czcionka Roboto Flex ma oś wysokości rosnącej ("YTAS"), która dostosowuje wysokość małych liter, a szerokość licznika ("XTRA") dostosowuje szerokość każdej litery.

Możesz zmienić wartości tych osi w ustawieniach FontVariation.

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

  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:

    • Zdefiniowanie barier dla wartości, które mogą akceptować. Jak widać w katalogu czcionek zmiennych, atrybut ascenderHeight (YTAS) ma minimalną wartość 649f, a maksymalnie 854f.
    • Przywróć 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. Korzystając z osi z konfiguracją czcionki, przekaż dodatkowe parametry do każdego wczytanego 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
    }

    Zwróć uwagę, że wysokość liter alfabetu łacińskiego została zwiększona, a pozostały tekst jest szerszy:

Trzy różne teksty z różnymi konfiguracjami czcionek zmiennych i ustawionymi niestandardowymi osiami. Niektóre z nich mają szersze litery z wysokością pisane małymi literami i są szersze niż wcześniej.
Rys. 3. Tekst przedstawiający niestandardowe osie ustawione na zmiennych czcionkach.

Dodatkowe materiały

Więcej informacji znajdziesz w następującym poście na blogu na temat czcionek zmiennych: