בדף הזה מוסבר איך להגדיר גופנים באפליקציית 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
הזה ל-composable של 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.7.5" }
Kotlin
dependencies { ... implementation("androidx.compose.ui:ui-text-google-fonts:1.7.5") }
- מאתחלים את
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 composable:
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
.
ניפוי באגים בהטמעה
כדי לוודא שהגופן מוריד בצורה נכונה, אפשר להגדיר בורר של פונקציית קורוטין לניפוי באגים. הכינוי מספק את ההתנהגות שצריך לבצע במקרה שהגופן לא נטען באופן אסינכרוני.
מתחילים ליצור 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 של הגופנים שניתן להורדה (במערכת התצוגה או בכלי ליצירת הודעות). יכול להיות שגופנים שנוספו לאחרונה לא ייטענו באפליקציה עם הודעת השגיאה 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), ) ) )
באמצעות ה-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 ) } } } }
כל רכיב
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 2 ב-Compose