בדף הזה מוסבר איך להגדיר גופנים באפליקציית Compose.
הגדרת גופן
Text יש פרמטר fontFamily שמאפשר להגדיר את הגופן שבו משתמשים ב-composable. כברירת מחדל, משפחות הגופנים serif, sans-serif, monospace ו-cursive כלולות:
@Composable fun DifferentFonts() { Column { Text("Hello World", fontFamily = FontFamily.Serif) Text("Hello World", fontFamily = FontFamily.SansSerif) } }
אפשר להשתמש במאפיין fontFamily כדי לעבוד עם גופנים מותאמים אישית ועם סוגי גופנים שמוגדרים בתיקייה res/font:
בדוגמה הזו מוסבר איך להגדיר fontFamily על סמך קובצי הגופן האלה באמצעות הפונקציה 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) )
אפשר להעביר את fontFamily הזה לרכיב Text שניתן להרכבה. מכיוון ש-fontFamily יכול לכלול משקלים שונים, אפשר להגדיר ידנית את fontWeight כדי לבחור את המשקל המתאים לטקסט:
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) }
במאמר מערכות עיצוב בהתאמה אישית ב-Compose מוסבר איך להגדיר את הטיפוגרפיה בכל האפליקציה.
גופנים שאפשר להוריד
החל מ-Compose 1.2.0, אפשר להשתמש בממשק ה-API של גופנים להורדה באפליקציית Compose כדי להוריד גופנים של Google באופן אסינכרוני ולהשתמש בהם באפליקציה.
בשלב הזה אין תמיכה בגופנים שאפשר להוריד מספקים בהתאמה אישית.
שימוש בגופנים להורדה באופן פרוגרמטי
כדי להוריד גופן באופן פרוגרמטי מתוך האפליקציה:
- מוסיפים את התלות:
Groovy
dependencies { ... implementation "androidx.compose.ui:ui-text-google-fonts:1.9.3" }
Kotlin
dependencies { ... implementation("androidx.compose.ui:ui-text-google-fonts:1.9.3") }
- מאתחלים את
GoogleFont.Providerעם פרטי הכניסה לגופנים של Google: הפרמטרים שהספק מקבל הם:val provider = GoogleFont.Provider( providerAuthority = "com.google.android.gms.fonts", providerPackage = "com.google.android.gms", certificates = R.array.com_google_android_gms_fonts_certs )
- רשות ספק הגופנים של Google Fonts.
- חבילת ספק הגופנים לאימות הזהות של הספק.
- רשימה של קבוצות גיבוב לאימות הזהות של הספק. אפשר למצוא את הגיבובים שנדרשים לספק Google Fonts
בקובץ
font_certs.xmlבאפליקציית הדוגמה Jetchat.
- הגדרת
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) )
FontWeightו-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 ) )
- מגדירים את
FontFamilyלשימוש בפונקציה הקומפוזבילית Text:
Text( fontFamily = fontFamily, text = "Hello World!" )
אפשר גם להגדיר טיפוגרפיה לשימוש ב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/*...*/ ), /*...*/ )
בשלב הבא, מגדירים את הטיפוגרפיה לעיצוב של האפליקציה:
MyAppTheme( typography = MyTypography )/*...*/
דוגמה לאפליקציה שמטמיעה גופנים להורדה ב-Compose יחד עם Material3 מופיעה באפליקציית הדוגמה Jetchat.
הוספת גופנים חלופיים
אתם יכולים להגדיר שרשרת של חלופות לגופן, למקרה שההורדה שלו תיכשל. לדוגמה, אם הגדרתם גופן להורדה כך:
// ... 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) )
כך מגדירים את ברירות המחדל של הגופן לשני המשקלים:
// ... 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) )
חשוב לוודא שאתם מוסיפים את הייבוא הנכון.
הגדרה של FontFamily באופן הזה יוצרת FontFamily שמכיל שתי שרשרות, אחת לכל משקל. מנגנון הטעינה ינסה לטעון קודם את הגופן באינטרנט, ואז את הגופן שנמצא בתיקיית המשאבים המקומית R.font.
ניפוי באגים בהטמעה
כדי לוודא שהגופן מורד בצורה תקינה, אפשר להגדיר handler של coroutine לניפוי באגים. הכינוי מספק את ההתנהגות של מה לעשות במקרה שהגופן לא נטען באופן אסינכרוני.
קודם כל יוצרים CoroutineExceptionHandler:
val handler = CoroutineExceptionHandler { _, throwable -> // process the Throwable Log.e(TAG, "There has been an issue: ", throwable) }
מעבירים אותו לשיטה createFontFamilyResolver כדי שהפותר ישתמש במטפל החדש:
CompositionLocalProvider( LocalFontFamilyResolver provides createFontFamilyResolver(LocalContext.current, handler) ) { Column { Text( text = "Hello World!", style = MaterialTheme.typography.bodyMedium ) } }
אפשר גם להשתמש ב-API של הספק isAvailableOnDevice כדי לבדוק אם הספק זמין והאישורים מוגדרים בצורה נכונה. כדי לעשות את זה, אפשר לקרוא לשיטה isAvailableOnDevice שמחזירה false אם הספק מוגדר בצורה לא נכונה.
val context = LocalContext.current LaunchedEffect(Unit) { if (provider.isAvailableOnDevice(context)) { Log.d(TAG, "Success!") } }
נקודות שחשוב לדעת
לוקח כמה חודשים עד שגופנים חדשים מ-Google Fonts זמינים ב-Android.
יש פער זמן בין הרגע שבו גופן נוסף ל-fonts.google.com לבין הרגע שבו הוא זמין דרך ה-API של גופנים להורדה (במערכת View או ב-Compose). יכול להיות שהגופנים החדשים שנוספו לא ייטענו באפליקציה עם השגיאה IllegalStateException.
כדי לעזור למפתחים לזהות את השגיאה הזו מבין סוגים אחרים של שגיאות בטעינת גופנים, הוספנו הודעה תיאורית לגבי החריגה ב-Compose עם השינויים שמופיעים כאן.
אם נתקלים בבעיות, אפשר לדווח עליהן באמצעות הכלי למעקב אחרי בעיות.
שימוש בגופנים משתנים
גופן משתנה הוא פורמט גופן שמאפשר לקובץ גופן אחד להכיל סגנונות שונים. בעזרת גופנים משתנים, אתם יכולים לשנות צירים (או פרמטרים) כדי ליצור את הסגנון המועדף עליכם. הצירים האלה יכולים להיות סטנדרטיים, כמו משקל, רוחב, הטיה וכתב נטוי, או מותאמים אישית, שמשתנים בין גופנים משתנים.
שימוש בגופנים משתנים במקום בקובצי גופנים רגילים מאפשר לכם להשתמש רק בקובץ גופן אחד במקום בכמה קבצים.
מידע נוסף על גופנים משתנים זמין במאגר הידע של Google Fonts, בקטלוג המלא של גופנים משתנים זמינים ובטבלה של הצירים הנתמכים לכל גופן.
במסמך הזה מוסבר איך מטמיעים גופן משתנה באפליקציית Compose.
טעינה של גופן משתנה
מורידים את הגופן המשתנה שרוצים להשתמש בו (לדוגמה, Roboto Flex) וממקמים אותו בתיקייה
app/res/fontבאפליקציה. מוודאים ש .ttfהקובץ שמוסיפים הוא גרסת הגופן המשתנה של הגופן, וששם קובץ הגופן הוא באותיות קטנות בלבד ולא מכיל תווים מיוחדים.כדי לטעון גופן משתנה, מגדירים
FontFamilyבאמצעות הגופן שמוצב בספרייה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), ) ) )
FontVariationAPI מאפשר לכם להגדיר צירים סטנדרטיים של גופנים, כמו משקל, רוחב ושיפוע. אלה צירים סטנדרטיים שזמינים בכל גופן משתנה. אפשר ליצור הגדרות שונות של הגופן בהתאם למקום שבו הגופן ישמש.גופנים משתנים זמינים רק ב-Android מגרסה O ואילך, לכן צריך להוסיף אמצעי הגנה ולהגדיר חלופה מתאימה:
// 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 }
מחלקים את ההגדרות לקבוצה של קבועים כדי שיהיה קל יותר להשתמש בהן שוב, ומחליפים את הגדרות הגופן בקבועים האלה:
// 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 }
מגדירים את הטיפוגרפיה של Material Design 3 כך שתשתמש ב-
FontFamily:// Type.kt val Typography = Typography( displayLarge = TextStyle( fontFamily = displayLargeFontFamily, fontSize = 50.sp, lineHeight = 64.sp, letterSpacing = 0.sp, /***/ ) )
בדוגמה הזו נעשה שימוש ב
displayLargeטיפוגרפיה של Material 3, שכוללת הגדרות שונות של גופן ברירת המחדל ושימושים מומלצים. לדוגמה, כדאי להשתמש ב-displayLargeלטקסט קצר וחשוב, כי זה הטקסט הכי גדול במסך.ב-Material 3, אפשר לשנות את ערכי ברירת המחדל של
TextStyleושלfontFamilyכדי להתאים אישית את הטיפוגרפיה. בקטע הקוד שלמעלה, מגדירים מופעים שלTextStyleכדי להתאים אישית את הגדרות הגופן לכל משפחת גופנים.אחרי שמגדירים את הטיפוגרפיה, מעבירים אותה אל M3
MaterialTheme:MaterialTheme( colorScheme = MaterialTheme.colorScheme, typography = Typography, content = content )
לבסוף, משתמשים ב-
Textcomposable ומציינים את הסגנון לאחד מסגנונות הטיפוגרפיה המוגדרים,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 ) } } } }
כל רכיב
Textניתן להגדרה באמצעות הסגנון של ערכת העיצוב Material שלו, והוא מכיל הגדרה שונה של גופן משתנה. אפשר להשתמש ב-MaterialTheme.typographyכדי לאחזר את הטיפוגרפיה שסופקה לרכיב הקומפוזבילי M3MaterialTheme.
שימוש בצירים בהתאמה אישית
גופנים יכולים לכלול גם צירים בהתאמה אישית. הם מוגדרים בתוך קובץ הגופן עצמו.
לדוגמה, לגופן Roboto Flex יש ציר של גובה האותיות עם הקו העליון ("YTAS"), שמשנה את הגובה של האותיות הקטנות עם הקו העליון, וציר של רוחב האותיות עם החלל הפנימי ("XTRA"), שמשנה את הרוחב של כל אות.
אפשר לשנות את הערך של הצירים האלה באמצעות ההגדרות של FontVariation.
מידע נוסף על הצירים המותאמים אישית שאפשר להגדיר לגופן זמין בטבלה של הצירים הנתמכים לכל גופן.
כדי להשתמש בצירים בהתאמה אישית, צריך להגדיר פונקציות לצירים
ascenderHeightו-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()) }
הפונקציות האלה מבצעות את הפעולות הבאות:
- הגדרת אמצעי בקרה לערכים שהם יכולים לקבל. כפי שאפשר לראות בקטלוג הגופנים המשתנים, ל-
ascenderHeight (YTAS)יש ערך מינימלי של649fוערך מקסימלי של854f. - מחזירים את הגדרת הגופן, כך שההגדרה מוכנה להוספה לגופן. בשיטה
FontVariation.Setting(), שם הציר (YTAS, XTRA) מוצפן, והערך מועבר כפרמטר.
- הגדרת אמצעי בקרה לערכים שהם יכולים לקבל. כפי שאפשר לראות בקטלוג הגופנים המשתנים, ל-
באמצעות הצירים עם הגדרת הגופן, מעבירים פרמטרים נוספים לכל
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 }
שימו לב שהגובה של האותיות הקטנות שעולות מעל השורה גדל, והטקסט האחר רחב יותר:
מקורות מידע נוספים
למידע נוסף, אפשר לקרוא את הפוסט הבא בבלוג על גופנים משתנים:
מומלץ
- הערה: טקסט הקישור מוצג כש-JavaScript מושבת
- מקורות מידע ב-Compose
- עיצוב טקסט
- Material Design 2 ב-Compose