En esta página, se describe cómo configurar las fuentes en tu app de Compose.
Cómo establecer la fuente
Text
tiene un parámetro fontFamily
para permitir la configuración de la fuente usada en el elemento componible. Según la configuración predeterminada, se incluyen las familias de fuentes serif, Sans Serif, monoespaciales y cursivas:
@Composable fun DifferentFonts() { Column { Text("Hello World", fontFamily = FontFamily.Serif) Text("Hello World", fontFamily = FontFamily.SansSerif) } }
Puedes usar el atributo fontFamily
para trabajar con fuentes personalizadas y tipos de letra definidos en la carpeta res/font
:
En este ejemplo, se muestra cómo definirías una fontFamily
según esas fuentes
y con la función 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) )
Puedes pasar este fontFamily
al elemento Text
componible. Debido a que un
fontFamily
puede incluir diferentes pesos. Puedes establecer fontWeight
de forma manual en
selecciona el grosor correcto para tu texto:
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) }
Para aprender a configurar la tipografía en toda la app, consulta Sistemas de diseño personalizado en Compose.
Fuentes descargables
Cómo comenzar en Compose 1.2.0 puedes usar la API de fuentes descargables en tu app de Compose para descargar Google fuentes de forma asíncrona y usarlas en tu app.
Por el momento, no se admiten las fuentes descargables que proporcionan los proveedores personalizados.
Usa fuentes descargables de manera programática
Para descargar una fuente de manera programática desde tu app, sigue estos pasos:
- Agrega la dependencia:
Groovy
dependencies { ... implementation "androidx.compose.ui:ui-text-google-fonts:1.7.0" }
Kotlin
dependencies { ... implementation("androidx.compose.ui:ui-text-google-fonts:1.7.0") }
- Inicializa el
GoogleFont.Provider
con las credenciales de Google Fonts: Los parámetros que recibe el proveedor son los siguientes:val provider = GoogleFont.Provider( providerAuthority = "com.google.android.gms.fonts", providerPackage = "com.google.android.gms", certificates = R.array.com_google_android_gms_fonts_certs )
- La autoridad del proveedor de fuentes de Google Fonts
- El paquete del proveedor de fuentes para verificar su identidad
- Una lista de conjuntos de hashes para los certificados a fin de verificar la identidad del proveedor Puedes encontrar los hashes necesarios para el proveedor de Google Fonts
en el archivo
font_certs.xml
de la App de ejemplo de Jetchat.
- Define un
FontFamily
: Puedes consultar otros parámetros para tu fuente, como el grosor y el estilo con// ... 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) )
FontWeight
yFontStyle
respectivamente:// ... 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 ) )
- Configura el
FontFamily
que se usa en la función de componibilidad de texto:
Text( fontFamily = fontFamily, text = "Hello World!" )
También puedes definir la tipografía para usar tu 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/*...*/ ), /*...*/ )
A continuación, establece la tipografía en el tema de tu app:
MyAppTheme( typography = MyTypography )/*...*/
Un ejemplo de una app que implementa fuentes descargables en Compose junto con Material3, Consulta la app de ejemplo Jetchat.
Agrega fuentes de resguardo
Puedes determinar una cadena de resguardo para tu fuente en caso de que esta no funcione descargar correctamente. Por ejemplo, si tienes definida la fuente descargable. así:
// ... 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) )
Puedes definir los valores predeterminados de la fuente para ambos grosores, de la siguiente manera:
// ... 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) )
Asegúrate de agregar las importaciones correctas.
Cuando defines FontFamily
de esta manera, se crea una FontFamily
que contiene dos cadenas, una por cada grosor. El mecanismo de carga intentará resolver la fuente en línea primero,
y, luego, la fuente ubicada en la carpeta local de recursos R.font
.
Cómo depurar tu implementación
Para ayudarte a verificar si la fuente se descarga correctamente, puedes definir un controlador de corrutinas de depuración. Tu controlador proporciona el comportamiento de lo que se debe hacer en caso de que la fuente no se cargue de forma asíncrona.
Para comenzar, crea un
CoroutineExceptionHandler
:
val handler = CoroutineExceptionHandler { _, throwable -> // process the Throwable Log.e(TAG, "There has been an issue: ", throwable) }
Pásalo a la
createFontFamilyResolver
para que el agente de resolución use el nuevo controlador:
CompositionLocalProvider( LocalFontFamilyResolver provides createFontFamilyResolver(LocalContext.current, handler) ) { Column { Text( text = "Hello World!", style = MaterialTheme.typography.bodyMedium ) } }
También puedes usar la API de isAvailableOnDevice
del proveedor para probar si está disponible y si los certificados están configurados de forma correcta. Para ello, puedes llamar al método isAvailableOnDevice
, que muestra el valor "false" si el proveedor no está bien configurado.
val context = LocalContext.current LaunchedEffect(Unit) { if (provider.isAvailableOnDevice(context)) { Log.d(TAG, "Success!") } }
Advertencias
Google Fonts tarda varios meses en habilitar las nuevas fuentes en Android.
Existe un intervalo de tiempo entre el momento en que se agrega una fuente en fonts.google.com y el momento en que está disponible desde la API de fuentes descargables (ya sea en el sistema de vistas o en Compose). Recién
las fuentes agregadas podrían no cargarse en tu app con una
IllegalStateException
Para ayudar a los desarrolladores a identificar este error entre otros tipos de errores de carga de fuentes,
agregamos mensajes descriptivos para la excepción en Compose con los cambios
aquí.
Si encuentras algún problema, infórmalo a través de la página correspondiente
de seguimiento.
Cómo usar fuentes variables
Una fuente variable es un formato de fuente que permite que un archivo de fuente contenga diferentes estilos. Con las fuentes variables, puedes modificar los ejes (o parámetros) para generar tu estilo preferido. Estos ejes pueden ser estándares, como de peso, ancho, inclinación, cursiva o personalizada, que difieren según las fuentes variables.
Usar fuentes variables en lugar de archivos de fuentes normales te permite tener solo una de fuentes en lugar de varios.
Para obtener más información sobre las fuentes variables, consulta Conocimiento de Google Fonts, el catálogo completo de fuentes variables disponibles y una tabla de los ejes compatibles para cada fuente.
En este documento, se muestra cómo implementar una fuente variable en tu app de Compose.
Carga una fuente variable
Descarga la fuente variable que quieras usar (por ejemplo, Roboto Flex) y colócalo en la carpeta
app/res/font
de tu app. Asegúrese de que el archivo ZIPttf
que agregues es la versión de fuente variable de la fuente y que el nombre de tu archivo de fuente está escrito en minúsculas y no contiene ningún carácter especial.Para cargar una fuente variable, define un elemento
FontFamily
usando la fuente que se encuentra en el Directoriores/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), ) ) )
La API de
FontVariation
te permite configurar ejes de fuentes estándar, como weight, width y slant. Estos son ejes estándar que son disponible con cualquier fuente variable. Puedes crear diferentes configuraciones del según el lugar donde se usará.Las fuentes variables solo están disponibles para Android O y versiones posteriores, por lo que debes agregar una una protección y configurar un resguardo adecuado:
// 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 }
Extrae la configuración a un conjunto de constantes para facilitar la reutilización y reemplaza el la configuración de la fuente con estas constantes:
// 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 }
Configura la tipografía de Material Design 3 para usar
FontFamily
:// Type.kt val Typography = Typography( displayLarge = TextStyle( fontFamily = displayLargeFontFamily, fontSize = 50.sp, lineHeight = 64.sp, letterSpacing = 0.sp, /***/ ) )
En este ejemplo, se usa la tipografía de Material 3
displayLarge
, que tiene diferentes la configuración de fuente predeterminada y los usos recomendados. Por ejemplo, debes usardisplayLarge
para el texto breve y fundamental, ya que es el texto más grande de la pantalla.Con Material 3, puedes cambiar los valores predeterminados de
TextStyle
yfontFamily
para personalizar la tipografía. En el fragmento anterior, configuras instancias deTextStyle
para personalizar la configuración de la fuente para cada familia de fuentes.Ahora que definiste la tipografía, pásala al
MaterialTheme
de M3:MaterialTheme( colorScheme = MaterialTheme.colorScheme, typography = Typography, content = content )
Por último, usa un elemento
Text
componible y especifica el estilo en uno de los elementos estilos de tipografía,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 ) } } } }
Cada elemento
Text
componible se configura mediante el estilo de su tema de Material y contiene una configuración de fuente variable diferente. Puedes usarMaterialTheme.typography
para recuperar la tipografía proporcionada a M3 ElementoMaterialTheme
componible.
Usar ejes personalizados
Las fuentes también pueden tener ejes personalizados. Estas se definen dentro del propio archivo de fuente.
Por ejemplo, la fuente Roboto Flex tiene el eje de altura ascendente ("YTAS"
), que
ajusta la altura de los ascendentes en minúscula, mientras que el ancho del contador ("XTRA"
)
ajusta el ancho de cada letra.
Puedes cambiar el valor de estos ejes con la configuración de FontVariation
.
Para obtener más información sobre los ejes personalizados que puedes configurar para una fuente, consulta la tabla de los ejes admitidos de cada fuente.
Para usar ejes personalizados, define funciones para el
ascenderHeight
personalizado y EjescounterWidth
: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()) }
Estas funciones hacen lo siguiente:
- Define barreras de seguridad para los valores que pueden aceptar. Como puedes ver en el
Catálogo de fuentes variables,
ascenderHeight (YTAS)
tiene un un valor mínimo de649f
y un máximo de854f
. - Muestra la configuración de la fuente, así que la configuración está lista para agregarla a la fuente. En el método
FontVariation.Setting()
, el nombre del eje (YTAS, XTRA
) está codificado y toma el valor como parámetro.
- Define barreras de seguridad para los valores que pueden aceptar. Como puedes ver en el
Catálogo de fuentes variables,
Usando los ejes con la configuración de la fuente, pasa parámetros adicionales a cada
Font
que se carga:@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 }
Observa que la altura de los ascendentes en minúscula ahora se incrementa, y otro texto es más amplio:
Recursos adicionales
Para obtener más información, consulta la siguiente entrada de blog sobre las fuentes variables:
Recomendaciones para ti
- Nota: El texto del vínculo se muestra cuando JavaScript está desactivado
- Recursos en Compose
- Aplica estilo al texto
- Material Design 2 en Compose