בדף הזה מוסבר איך להגדיר גופנים באפליקציית 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 מוסבר איך להגדיר את הטיפוגרפיה בכל האפליקציה.
גופנים שניתנים להורדה
החל מגרסה 1.2.0 של Compose, אתם יכולים להשתמש ב-API של גופנים שניתנים להורדה באפליקציית Compose כדי להוריד גופנים של Google באופן אסינכרוני ולהשתמש בהם באפליקציה.
כרגע אין תמיכה בגופנים שניתנים להורדה מספקים בהתאמה אישית.
שימוש בגופנים שניתנים להורדה באופן פרוגרמטי
כדי להוריד גופן באופן פרוגרמטי מתוך האפליקציה, פועלים לפי השלבים הבאים:
- מוסיפים את התלות:
מגניב
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") }
- מפעילים את
GoogleFont.Providerעם פרטי הכניסה ל-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 )
- הרשות של ספק הגופנים של Google Fonts.
- חבילת ספק הגופנים לאימות הזהות של הספק.
- רשימה של קבוצות גיבוב (hash) של האישורים לאימות הזהות של הספק. את הגיבובים שנדרשים לספק 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 )/*...*/
באפליקציה לדוגמה Jetchat אפשר לראות דוגמה לאפליקציה שמטמיעה גופנים שניתנים להורדה ב-Compose יחד עם Material3.
הוספת גופנים חלופיים
אתם יכולים להגדיר שרשרת של חלופות לגופן למקרה שהגופן לא יורד כמו שצריך. לדוגמה, אם הגדרתם את הגופן שניתן להורדה כך:
// ... 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 לניפוי באגים. ה-handle מספק את ההתנהגות של מה לעשות במקרה שהגופן לא נטען באופן אסינכרוני.
קודם כל, יוצרים CoroutineExceptionHandler:
val handler = CoroutineExceptionHandler { _, throwable -> // process the Throwable Log.e(TAG, "There has been an issue: ", throwable) }
מעבירים אותו ל-method createFontFamilyResolver כדי שה-resolver ישתמש ב-handler החדש:
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 עם השינויים שכאן.
אם נתקלתם בבעיות, אתם יכולים לדווח עליהן באמצעות Issue Tracker.
שימוש בגופנים משתנים
גופן משתנה הוא פורמט של גופן שמאפשר לקובץ גופן אחד להכיל סגנונות שונים. בגופנים משתנים, אתם יכולים לשנות את הצירים (או הפרמטרים) כדי ליצור את הסגנון המועדף עליכם. הצירים האלה יכולים להיות סטנדרטיים, כמו משקל, רוחב, שיפוע וכתב נטוי, או מותאמים אישית, והם משתנים בין גופנים משתנים.
שימוש בגופנים משתנים במקום בקובצי גופנים רגילים מאפשר לכם להשתמש בקובץ גופן אחד במקום בכמה קבצים.
למידע נוסף על גופנים משתנים, אפשר לעיין במאגר הידע של 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), ) ) )
באמצעות ה-API של
FontVariationאפשר להגדיר צירי גופנים סטנדרטיים כמו עובי, רוחב ושיפוע. אלה צירים סטנדרטיים שזמינים בכל גופן משתנה. אתם יכולים ליצור הגדרות שונות של הגופן בהתאם למקום שבו תשתמשו בו.גופנים משתנים זמינים רק בגרסאות 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 )
לבסוף, משתמשים בפונקציה קומפוזבילית
Textומציינים את הסגנון לאחד מסגנונות הטיפוגרפיה המוגדרים,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 ) } } } }
כל רכיב Composable של
Textמוגדר באמצעות הסגנון של התאמת העיצוב של Google Material Design, ומכיל הגדרה שונה של גופן משתנה. אתם יכולים להשתמש ב-MaterialTheme.typographyכדי לאחזר את הטיפוגרפיה שסופקה ל-MaterialThemeהקומפוזבילי של M3.
שימוש בצירים בהתאמה אישית
לגופנים יכולים להיות גם צירים בהתאמה אישית. הם מוגדרים בקובץ הגופן עצמו.
לדוגמה, לגופן Roboto Flex יש את הציר ascender height ("YTAS"), שמתאים את הגובה של האותיות הקטנות, ואת הציר counter width ("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