Typeface — هي فئة من SDK أندرويد من حزمة android.graphics تُمثّل قطع الخط وتستخدم لتخصيص النص في TextView ومكونات واجهة المستخدم الأخرى. Typeface تحدد عائلة الخط، وزنه (normal, bold) ونمطه (normal, italic). وفقًا ل«Google Developers»، Typeface تدعم التحميل من ملفات TTF، OTF، خطوط XML وموارد النظام. هي الفئة المركزية لإدارة الطباعة في تطبيقات أندرويد.
النقاط الرئيسية
Typeface — هي فئة Android تُغلّف معلومات الخط: عائلته (Roboto, Arial, Serif) ومعدلات النمط (bold, italic). على عكس UIFont في iOS، Typeface لا تحتوي على معلومات الحجم — يتم تعيين حجم النص بشكل منفصل عبر خاصية textSize في TextView أو TextStyle في Spannable. Typeface تكون مسؤولة فقط عن القطع وتصميم الخط.
الفئة متاحة في جميع مستويات API. قبل Android 4.4، كان Typeface يدعم فقط مجموعة محدودة من خطوط النظام: DEFAULT، DEFAULT_BOLD، MONOSPACE، SERIF، SANS_SERIF. بدءًا من Android 8.0 (API 26)، تمت إضافة دعم تحميل الخطوط المخصصة عبر موارد XML، وأضاف Android 10 دعم الخطوط المتغيرة.
يوفر Android عدة مثالات Typeface مضمنة: Typeface.DEFAULT — خط النظام Roboto (Material) أو Noto (AOSP)، DEFAULT_BOLD — النسخة العريضة، MONOSPACE — خط أحادي العرض للكود، SERIF — خط مع الركن (Noto Serif)، SANS_SERIF — خط بلا ركن (Noto Sans). هذه الثوابت متاحة بدون سياق ولا تتطلب أذونات قراءة الملفات.
يستخدم نظام Android Typeface لعرض جميع النصوص، بما في ذلك واجهة النظام، العناوين، التعليقات والإشعارات. يمكن لكل تطبيق تجاوز الخط الافتراضي عبر الموضوع (android:fontFamily) أو برمجيًا عبر setTypeface(). ينطبق Typeface على جميع المكونات الموروثة من TextView: الأزرار، EditText والعروض المخصصة.
Android 8.0+ يسمح بإضافة الخطوط إلى res/font واستخدامها عبر موارد XML. يتم وضع ملف الخط (TTF أو OTF) في res/font، بعد ذلك يتم إنشاء مرجع R.font.font_name. يتم تحميل Typeface عبر ResourcesCompat.getFont(context, R.font.font_name). هذه الطريقة مفضّلة لأن الخط يتم تجميعه في APK ويدعم أنظمة بناء ProGuard.
يدعم نهج المورد أيضًا عائلات الخطوط عبر ملف XML في res/font: يمكنك تحديد ملفات متعددة لأنماط مختلفة (regular, bold, italic) وسيختار النظام الملف المناسب تلقائيًا عند استدعاء setTypeface. هذا يبسّط الطباعة — يكفي تعيين fontFamily في الموضوع، وسيختار Android الملف الصحيح تلقائيًا.
الطريقة Typeface.create(Typeface family, int style) تنشئ مثال خط بالعائلة والنمط المحددين. إذا كانت العائلة تمتلك النمط المطلوب، يتم إعادة المثال الموجود. إذا كان النمط مفقودًا، يقوم Android بتركيبه — تطبيق الخط العريض المزيّف أو المائل الاصطناعي على الخط الأساسي.
val boldTypeface = Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD)
val italicTypeface = Typeface.create(Typeface.MONOSPACE, Typeface.ITALIC)
val customTypeface = ResourcesCompat.getFont(context, R.font.montserrat_regular)
textView.typeface = boldTypeface
قد يبدو الخط العريض المركّب ذا جودة منخفضة على الخطوط الرفيعة. للحصول على أفضل نتيجة، استخدم ملف خط مع قطع bold حقيقي. Typeface.create() مع نمط غير موجود لا ترمي استثناءً، بل تعيد أقرب الاختيارات المتاحة.
لتحميل Typeface من assets، استخدم Typeface.createFromAsset(assetManager, path). يتم وضع الخط في الملف src/main/assets/fonts/، ويتم تحديد المسار بالنسبة لـ assets. تعمل هذه الطريقة على جميع إصدارات Android، ولكنها لا تدعم عائلات الخطوط وتتطلب تحديد ملف محدد لكل قطع.
الطريقة Typeface.createFromFile(File) تحمّل خطًا من أي ملف على نظام الملفات. هذا مفيد للخطوط المحمّلة من الشبكة أو المنسوخة إلى التخزين الداخلي للتطبيق. createFromFile أيضًا لا تتطلب سياقًا، وما يجعلها مناسبة للمهام الخلفية، ولكن يجب أن يكون الملف قابلًا للقراءة.
تحميل Typeface بشكل متكرر من assets عبر createFromAsset قد يؤدي إلى إنشاء كائنات مكررة. كل استدعاء لـ createFromAsset يعيد تحميل الملف. يوصى بتنفيذ تخزين مؤقت Typeface باستخدام HashMap، حيث يكون المفتاح هو مسار الملف والقيمة هي الكائن المحمّل. هذا ذو صلة خاصة للقوائم بأنواع خطوط مختلفة.
object TypefaceCache {
private val cache = mutableMapOf<String, Typeface>()
fun getTypeface(context: Context, filename: String): Typeface {
return cache.getOrPut(filename) {
Typeface.createFromAsset(context.assets, "fonts/$filename")
}
}
}
// Usage
val typeface = TypefaceCache.getTypeface(context, "Roboto-Bold.ttf")
يضمن التخزين المؤقت في الذاكرة أن الخط يتم تحميله مرة واحدة فقط خلال جلسة التطبيق. عند تغيرات التكوين (تدوير الشاشة)، يبقى التخزين المؤقت قائمًا لأنه يوجد في كائن companion. لمسح التخزين المؤقت عند نقص الذاكرة، استخدم WeakHashMap أو استمع لـ onTrimMemory.
يتم تطبيق Typeface على TextView عبر الطريقة setTypeface(Typeface tf) أو setTypeface(Typeface tf, int style). الخيار الثاني يسمح بتغيير النمط (bold/italic) بالنسبة للخط الحالي. في XML، يتم استخدام السمة android:fontFamily مع مرجع إلى الخط أو عائلة النظام. للإعداد البرمجي، استدعاء setTypeface(monospaceTypeface) يستبدل الخط بالمحدد.
يؤثر Typeface على كل نص في TextView. إذا كانت خطوط مختلفة مطلوبة في سطر واحد، استخدم SpannableString مع TypefaceSpan. TypefaceSpan يقبل Typeface أو عائلة وينطبق على نطاق من الأحرف. هذه هي الطريقة الوحيدة لخلط الخطوط داخل TextView واحد بدون مكونات متداخلة.
طبّق TypefaceSpan على جزء من السلسلة فقط. على سبيل المثال، قيمة متغير في النص يجب أن تكون أحادية العرض بينما بقية النص يبقى بخط النظام. أنشئ SpannableString وعيّن TypefaceSpan مع Typeface MONOSPACE على النطاق المطلوب. بقية النص تحتفظ بخط TextView الأصلي.
val text = "Code: variableName"
val spannable = SpannableString(text)
spannable.setSpan(
TypefaceSpan(Typeface.MONOSPACE),
5, text.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
spannable.setSpan(
ForegroundColorSpan(Color.BLUE),
5, text.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
textView.text = spannable
النص «variableName» سيظهر بخط أحادي العرض باللون الأزرق، بينما تبقى كلمة «Code:» بخط النظام. يمكن دمج TypefaceSpan مع أي أنواع أخرى من الأسبان للتحكم الدقيق في كل قطعة نص.
Android يدعم عدة تنسيقات للخطوط: TrueType (TTF)، OpenType (OTF) و Web Open Font Format (WOFF2) بدءًا من Android 10. TTF و OTF هما التنسيقان الرئيسيان للخطوط المخصصة. خطوط XML (Font Family) ليست تنسيقًا منفصلًا، ولكنها تعمل كوصف للملف الذي يجب استخدامه لكل قطع.
لاستخدام خط مخصص عبر res/font، أنشئ ملف XML للعائلة يحدد مسارات ملفات الخط للأنماط regular، bold و italic. ثم في موضوع التطبيق، حدّد android:fontFamily="@font/custom_family". جميع كائنات TextView التي تستخدم هذا الموضوع ستحصل تلقائيًا على القطع الصحيح لكل نمط.
إذا تم تحميل خط من الشبكة، احفظه في filesDir أو cacheDir وحمّله عبر Typeface.createFromFile. بعد التحميل، حدّث Typeface في TextView. للتحميل غير المتزامن، استخدم coroutine أو DownloadManager، وبعد الاكتمال، انشر في سلسلة واجهة المستخدم عبر Handler. هذا سيناريو نموذجي للتطبيقات ذات الطباعة المخصصة المحمّلة عند الطلب.
// Save font file to internal storage
val fontFile = File(context.cacheDir, "downloaded-font.otf")
fontFile.outputStream().use { output ->
// inputStream from network
inputStream.copyTo(output)
}
// Create Typeface from file
val downloadedTypeface = Typeface.createFromFile(fontFile)
textView.typeface = downloadedTypeface
قبل التحميل، تحقّق من توافر الملف: إذا كان الملف تالفًا أو غير صالح، يرمي Typeface.createFromFile RuntimeException. يوصى بتغليف الاستدعاء في try-catch وفي حال الخطأ العودة إلى خط النظام الافتراضي.
في Jetpack Compose، لا يتم استخدام Typeface من SDK Android بشكل مباشر. بدلًا من ذلك، يوفر Compose FontFamily و FontWeight للطباعة. يتم تحميل FontFamily عبر Font.Resource و Font.File. يتم تعريف نظام الطباعة في Compose عبر MaterialTheme.typography، حيث يمكن تعيين FontFamily مخصص لكل نمط (h1، body1، button).
لتحميل خط من الموارد، يستخدم Compose Font(R.font.font_name, weight, style). يتم تحميل خط من assets عبر Font(assetPath = "fonts/custom.otf", weight, style). بعد تعريف الخط، يتم إرساله إلى Typography، ثم تطبيقه عبر MaterialTheme.typography.bodyLarge وأنماط مماثلة.
إذا كان لديك Typeface موجود منشأ عبر SDK Android، يمكن استخدامه في Compose عبر TypefaceAdapter أو بإنشاء FontFamily بناءً على Typeface. احصل على Typeface من Typeface.create وأرسله إلى FontFamily.Custom(listOf(Font(typeface))). ولكن يوصى بالنهج الأصلي مع Font.Resource لأنه أفضل تحسينًا لـ Compose.
تحميل الخطوط من الملفات هي عملية مكلفة في الأساس. كل استدعاء لـ Typeface.createFromAsset أو Typeface.createFromFile يقرأ الملف من القرص، يحلّله وينشئ كائن Typeface. للخطوط بحجم 1-2 ميجابايت، يستغرق ذلك 10-50 ملي ثانية على البدء البارد. تخزين Typeface مؤقتًا هو ممارسة إلزامية للتطبيقات ذات الخطوط المخصصة.
SDK Android لا يخزن مؤقتًا الخطوط المنشأة عبر createFromAsset أو createFromFile. بخلاف خطوط النظام، التي تتم تحميلها مسبقًا في عملية Zygote، فإن الخطوط المخصصة تتم تحميلها عند كل وصول. يوصى باستخدام LruCache أو ConcurrentHashMap مع محدد خط كمفتاح. حجم التخزين المؤقت 10-20 كائنًا يغطي مجموعة خطوط التطبيق النموذجية.
Android 8.0+ يحسّن تحميل الخطوط من خلال XML Font Family. عند تحديد android:fontFamily="@font/my_family" في تخطيط XML، يقوم Android بتحميل الخط بكسل — فقط عندما يصبح المكون مرئيًا. كما أن النظام يخزن مؤقتًا الخطوط المحمّلة عبر ResourcesCompat.getFont() في تخزين مؤقت عالمي للعمليات. هذا يجعل نهج المورد الأكثر كفاءة.
عند استخدام Typeface في محولات RecyclerView، من المهم عدم تحميل الخط في طريقة onBindViewHolder. قم بالتحميل مرة واحدة عند إنشاء المحول أو استخدم ViewHolder مع Typeface محمّل مسبقًا. إذا كان كل عنصر قائمة يتطلب خطًا فريدًا، نفّذ تخزينًا مؤقتًا باستخدام WeakHashMap وامسحه عند التمرير خلف المواقع المرئية لتوفير الذاكرة.
الأسئلة الشائعة
Typeface — هي مثال خط محدد للاستخدام البرمجي. FontFamily — هي مورد XML يصف مجموعة من ملفات الخط لأنماط مختلفة (regular، bold، italic). في وقت التنفيذ، يتم تحويل FontFamily إلى Typeface عبر ResourcesCompat.getFont. يمكن إنشاء Typeface مباشرة من الملف، بدون استخدام FontFamily.
استخدم Typeface.createFromFile(File) أو Typeface.DEFAULT. هذه الطرق لا تتطلب سياقًا لأنها تعمل مع نظام الملفات أو الثوابت المضمنة. للتحميل من assets أو الموارد، السياق ضروري لأن الوصول إلى AssetManager وموارد التطبيق مطلوب.
لا، WebView يستخدم خاصية CSS font-family لتحديد الخطوط. لاستخدام خط مخصص في WebView، ضع ملف الخط في assets وحدّده عبر @font-face في CSS. Typeface من SDK Android تعمل فقط مع مكونات واجهة المستخدم الأصلية (TextView ومورثاته).
نعم، بدءًا من Android 10 (API 29). تتم تحميل الخطوط المتغيرة عبر ResourcesCompat.getFont أو Typeface.createFromFile. لتكوين محاور التباين (weight، width)، استخدم FontStyle في Compose أو سمات XML. لا يمكن تغيير المحاور برمجيًا إلا عبر API منخفضة لـ Skia.
الأسباب الأكثر شيوعًا: ملف الخط مفقود في المشروع، اسم الملف غير صحيح، الخط تالف، أو يتم استخدام نمط مركّب غير موجود في الملف. تحقّق من إضافة الملف إلى res/font أو assets، وأن اسمه محدد بدون امتداد في حال استخدام نهج المورد.
الملخص
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.