Utilizzare i caratteri

Questa pagina descrive come impostare i caratteri nell'app Scrivi.

Imposta carattere

Text ha un parametro fontFamily per consentire di impostare il carattere utilizzato nel composable. Per impostazione predefinita, sono incluse le famiglie di caratteri con grazie, senza grazie, monodimensionale e corsivo:

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

Le parole

Puoi utilizzare l'attributo fontFamily per lavorare con caratteri e tipi di carattere personalizzati definiti nella cartella res/font:

Raffigurazione grafica della cartella res > font nell'ambiente di sviluppo

Questo esempio mostra come definiresti un fontFamily in base a questi file di caratteri e utilizzando la funzione 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)
)

Puoi passare questo fontFamily al composable Text. Poiché un fontFamily può includere ponderazioni diverse, puoi impostare manualmente fontWeight per selezionare la ponderazione corretta per il testo:

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)
}

Le parole

Per scoprire come impostare la tipografia nell'intera app, consulta Sistemi di design personalizzati in Compose.

Caratteri scaricabili

A partire da Compose 1.2.0, puoi utilizzare l'API dei caratteri scaricabili nell'app Compose per scaricare i caratteri Google in modo asincrono e utilizzarli nella tua app.

Il supporto per i caratteri scaricabili forniti da fornitori personalizzati non è attualmente disponibile.

Utilizza i caratteri scaricabili in modo programmatico

Per scaricare un carattere in modo programmatico dall'app, segui questi passaggi:

  1. Aggiungi la dipendenza:

    Groovy

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

    Kotlin

    dependencies {
        ...
        implementation("androidx.compose.ui:ui-text-google-fonts:1.7.5")
    }
  2. Inizializza GoogleFont.Provider con le credenziali per 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
    )
    I parametri ricevuti dal provider sono:
    • L'autorità del fornitore dei caratteri per Google Fonts.
    • Il pacchetto del provider di caratteri per verificare l'identità del provider.
    • Un elenco di insiemi di hash per i certificati per verificare l'identità del fornitore. Puoi trovare gli hash richiesti per il provider Google Fonts nel file font_certs.xml nell' app di esempio Jetchat.
  3. Definisci un 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)
    )
    Puoi eseguire query relative ad altri parametri per il carattere, come lo spessore e lo stile, con FontWeight e FontStyle rispettivamente:
    // ...
     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. Configura FontFamily da utilizzare nella funzione componibile di testo:

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

Puoi anche definire la tipografia per utilizzare il tuo 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/*...*/
    ),
    /*...*/
)

Imposta la tipografia sul tema dell'app:

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

Per un esempio di app che implementa caratteri scaricabili in Compose insieme a Material3, guarda l'app di esempio Jetchat.

Aggiungere caratteri di riserva

Puoi determinare una catena di alternative per il carattere nel caso in cui non riesca a scaricarsi correttamente. Ad esempio, se hai definito il carattere scaricabile come segue:

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

Puoi definire i valori predefiniti per il carattere per entrambi i pesi come segue:

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

Assicurati di aggiungere le importazioni corrette.

Se definisci FontFamily in questo modo, viene creato un FontFamily contenente due catene, una per peso. Il meccanismo di caricamento tenterà prima di risolvere il carattere online, poi quello che si trova nella cartella delle risorse R.font locale.

Eseguire il debug dell'implementazione

Per aiutarti a verificare se il carattere viene scaricato correttamente, puoi definire un gestore di coroutine di debug. L'handle fornisce il comportamento da seguire nel caso in cui il caricamento del carattere non riesca in modo asincrono.

Per iniziare, crea una CoroutineExceptionHandler:

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

Passalo al metodo createFontFamilyResolver affinché il resolver utilizzi il nuovo gestore:

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

Puoi anche utilizzare l'API isAvailableOnDevice del fornitore per verificare se il fornitore è disponibile e se i certificati sono configurati correttamente. Per farlo, puoi chiamare il metodo isAvailableOnDevice che restituisce false se il provider non è configurato correttamente.

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

Limitazioni

Ci vogliono diversi mesi per rendere disponibili nuovi caratteri su Android per Google Fonts. C'è un certo intervallo di tempo tra il momento in cui un carattere viene aggiunto in fonts.google.com e il momento in cui questo è disponibile tramite l'API per i caratteri scaricabili (nel sistema di visualizzazione o in Compose). I caratteri aggiunti di recente potrebbero non essere caricati nella tua app con un elemento IllegalStateException. Per aiutare gli sviluppatori a identificare questo errore rispetto ad altri tipi di errori di caricamento dei caratteri, abbiamo aggiunto messaggi descrittivi per l'eccezione in Scrivi con le modifiche qui. Se riscontri problemi, segnalali utilizzando il tracker dei problemi.

Utilizzare i caratteri variabili

Un carattere variabile è un formato di carattere che consente a un file di caratteri di contenere stili diversi. Con i caratteri variabili, puoi modificare gli assi (o i parametri) per generare il tuo stile preferito. Questi assi possono essere standard, come peso, larghezza, inclinazione e corsivo, oppure personalizzati, che variano a seconda dei caratteri variabili.

Cinque configurazioni dello stesso carattere variabile con valori di asse diversi.
Figura 1. Testo che utilizza lo stesso carattere variabile personalizzato con valori dell'asse diversi.

L'utilizzo di caratteri variabili anziché di file di caratteri normali ti consente di avere un solo file di caratteri anziché più.

Per ulteriori informazioni sui caratteri variabili, consulta le risorse di Google Fonts, l'intero catalogo dei caratteri variabili disponibili e una tabella degli assi supportati per ogni carattere.

Questo documento mostra come implementare un carattere variabile nell'app Compose.

Caricare un carattere variabile

  1. Scarica il carattere della variabile che vuoi utilizzare (ad esempio Roboto Flex) e inseriscilo nella cartella app/res/font dell'app. Assicurati che il filettf che aggiungi è la versione con carattere variabile del carattere e che il nome del file del carattere sia scritto in minuscolo e non contenga caratteri speciali.

  2. Per caricare un carattere variabile, definisci un FontFamily utilizzando il carattere inserito nella directory 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),
                )
            )
        )

    L'API FontVariation consente di configurare assi dei caratteri standard come weight, width e slant. Si tratta di assi standard disponibili con qualsiasi carattere variabile. Puoi creare diverse configurazioni del carattere in base a dove verrà utilizzato.

  3. I caratteri variabili sono disponibili solo per le versioni di Android O e successive, quindi aggiungi un parametro di sicurezza e configura un'opzione di riserva appropriata:

    // 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. Estrai le impostazioni in un insieme di costanti per un riutilizzo più facile e sostituisci le impostazioni dei caratteri con queste costanti:

    // 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. Configura la tipografia Material Design 3 per utilizzare FontFamily:

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

    Questo esempio utilizza la displayLarge tipografia Material 3, che ha impostazioni dei caratteri predefinite e usi consigliati diversi. Ad esempio, dovresti usare displayLarge per il testo breve e fondamentale, perché è il testo più grande sullo schermo.

    Con Material 3, puoi modificare i valori predefiniti di TextStyle e fontFamily per personalizzare la tipografia. Nello snippet riportato sopra, configuri le istanze di TextStyle per personalizzare le impostazioni dei caratteri per ciascuna famiglia di caratteri.

  6. Ora che hai definito la tipografia, passala a M3 MaterialTheme:

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

  7. Infine, utilizza un composable Text e specifica lo stile di uno degli stili di tipografia definiti, 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
                    )
                }
            }
        }
    }

    Ogni composable Text è configurato tramite lo stile del tema Material e contiene una configurazione del carattere variabile diversa. Puoi utilizzare MaterialTheme.typography per recuperare la tipografia fornita al composable M3 MaterialTheme.

Tre testi diversi, tutti con configurazioni di caratteri diverse.
Figura 2. Font variabile applicato in tre diverse configurazioni.

Utilizzare assi personalizzati

I caratteri possono anche avere assi personalizzati. Questi sono definiti all'interno del file del carattere stesso. Ad esempio, il carattere Roboto Flex ha l'asse Altezza ascendente ("YTAS"), che consente di regolare l'altezza delle ascisse minuscole, mentre la larghezza del contatore ("XTRA") consente di regolare la larghezza di ogni lettera.

Puoi modificare il valore di questi assi con le impostazioni FontVariation.

Per ulteriori informazioni sugli assi personalizzati che puoi configurare per un carattere, consulta la tabella degli assi supportati per ogni carattere.

  1. Per utilizzare gli assi personalizzati, definisci le funzioni per gli assi ascenderHeight e counterWidth personalizzati:

    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())
    }

    Queste funzioni svolgono le seguenti operazioni:

    • Definisci delle limitazioni per i valori che possono essere accettati. Come puoi vedere nel catalogo dei caratteri variabili, ascenderHeight (YTAS) ha un valore minimo di 649f e un valore massimo di 854f.
    • Ripristina l'impostazione del carattere in modo che la configurazione sia pronta per essere aggiunta al carattere. Nel metodo FontVariation.Setting(), il nome dell'asse (YTAS, XTRA) è hardcoded e prende il valore come parametro.
  2. Utilizzando gli assi con la configurazione del carattere, passa parametri aggiuntivi a ogni Font caricato:

    @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
    }

    Nota che l'altezza dei tratti ascendenti minuscoli è ora aumentata e il resto del testo è più largo:

Tre diversi testi che mostrano configurazioni diverse per i caratteri variabili, con assi personalizzati impostati: alcuni hanno asce ascendenti minuscole più alte e sono più larghi di prima.
Figura 3. Testo che mostra gli assi personalizzati impostati sui caratteri variabili.

Risorse aggiuntive

Per ulteriori informazioni, consulta il seguente post del blog sui caratteri variabili: