توضّح هذه الصفحة كيفية ضبط الخطوط في تطبيق Compose.
ضبط الخط
تحتوي السمة Text على مَعلمة fontFamily تتيح ضبط الخط المستخدَم في الدالة المركّبة. تتضمّن مجموعات الخطوط التلقائية 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، يمكنك استخدام واجهة برمجة التطبيقات للخطوط القابلة للتنزيل في تطبيق Compose لتنزيل خطوط Google بشكل غير متزامن واستخدامها في تطبيقك.
لا تتوفّر حاليًا إمكانية استخدام الخطوط القابلة للتنزيل التي يقدّمها موفّرو خدمات مخصّصون.
استخدام الخطوط القابلة للتنزيل آليًا
لتنزيل خط آليًا من داخل تطبيقك، اتّبِع الخطوات التالية:
- أضِف التبعية:
أنيق
dependencies { ... implementation "androidx.compose.ui:ui-text-google-fonts:1.11.3" }
Kotlin
dependencies { ... implementation("androidx.compose.ui:ui-text-google-fonts:1.11.3") }
- ابدأ
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
- حزمة موفّر الخطوط للتحقّق من هوية الموفّر
- قائمة بمجموعات من الرموز البرمجية لشهادات التحقّق من هوية الموفّر
يمكنك العثور على الرموز البرمجية المطلوبة لموفّر 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 المحلي.
تصحيح أخطاء عملية التنفيذ
لمساعدتك في التحقّق مما إذا كان يتم تنزيل الخط بشكل صحيح، يمكنك تحديد معالج روتيني فرعي لتصحيح الأخطاء. يوفّر المعالج السلوك المطلوب اتّخاذه في حال تعذّر تحميل الخط بشكل غير متزامن.
ابدأ بإنشاء
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 ) } }
يمكنك أيضًا استخدام واجهة برمجة التطبيقات
isAvailableOnDevice
من الموفّر لاختبار ما إذا كان الموفّر متاحًا وتم ضبط الشهادات
بشكل صحيح. لإجراء ذلك، يمكنك استدعاء طريقة isAvailableOnDevice التي تعرض القيمة "خطأ" إذا تم ضبط الموفّر بشكل غير صحيح.
val context = LocalContext.current LaunchedEffect(Unit) { if (provider.isAvailableOnDevice(context)) { Log.d(TAG, "Success!") } }
المحاذير
يستغرق توفير خطوط جديدة على Android عدة أشهر في Google Fonts.
هناك فجوة زمنية بين وقت إضافة خط في
fonts.google.com ووقت توفّره من خلال
واجهة برمجة التطبيقات للخطوط القابلة للتنزيل (إما في نظام العرض أو في Compose). قد يتعذّر تحميل الخطوط التي تمت إضافتها حديثًا في تطبيقك مع ظهور
IllegalStateException.
لمساعدة المطوّرين في تحديد هذا الخطأ بدلاً من أنواع أخرى من أخطاء تحميل الخطوط،
أضفنا رسائل وصفية للاستثناء في Compose مع التغييرات
هنا.
إذا واجهت أي مشاكل، يُرجى الإبلاغ عنها باستخدام أداة تتبُّع
المشاكل.
استخدام الخطوط المتغيّرة
الخط المتغيّر هو تنسيق خط يسمح لملف خط واحد باحتواء أنماط مختلفة. باستخدام الخطوط المتغيّرة، يمكنك تعديل المحاور (أو المَعلمات) لإنشاء النمط المفضّل لديك. يمكن أن تكون هذه المحاور عادية، مثل الوزن والعرض والميل والخط المائل، أو مخصّصة، وتختلف بين الخطوط المتغيّرة.
يسمح لك استخدام الخطوط المتغيّرة بدلاً من ملفات الخطوط العادية بامتلاك ملف خط واحد فقط بدلاً من ملفات متعددة.
لمزيد من المعلومات الأساسية عن الخطوط المتغيّرة، اطّلِع على مقالة Google Fonts Knowledge، والكتالوج الكامل للخطوط المتغيّرة المتاحة ، وجدول المحاور المتوافقة لكل خط.
يوضّح هذا المستند كيفية تنفيذ خط متغيّر في تطبيق 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), ) ) )
تتيح لك واجهة برمجة التطبيقات
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 }
اضبط الطباعة في التصميم المتعدد الأبعاد 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لتخصيص إعدادات الخط لكل مجموعة خطوط.بعد تحديد الطباعة، مرِّرها إلى
MaterialThemeفي M3: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
- تنسيق النص
- التصميم المتعدد الأبعاد 2 في Compose