توضّح هذه الصفحة كيفية ضبط الخطوط في تطبيق 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.0" }
Kotlin
dependencies { ... implementation("androidx.compose.ui:ui-text-google-fonts:1.11.0") }
- يمكنك تهيئة الـ
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
API من الموفّر لاختبار ما إذا كان الموفّر متاحًا وتم ضبط الشهادات بشكلٍ صحيح. لإجراء ذلك، يمكنك استدعاء طريقة 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