Font Descriptor هو كائن UIFontDescriptor في iOS و NSFontDescriptor في macOS الذي يغلف جميع البيانات الوصفية للخط: العائلة، النمط، الحجم، التباعد بين الأحرف، تباعد الأسطر وسمات الطباعة. بدلاً من إنشاء خط مباشرة عبر UIFont(name:size:)، يصف المطور الخصائص المطلوبة من خلال واصف، ويقوم النظام بتحديد أفضل تطابق من الخطوط المتاحة. وفقاً لوثائق مطوري Apple، يدعم UIFontDescriptor أكثر من 20 سمة للخط ويستخدم في جميع أطر الطباعة في iOS — من UIKit إلى Core Text و SwiftUI.
النقاط الرئيسية
Font Descriptor هو كائن يصف خصائص الخط كمجموعة من أزواج المفتاح والقيمة، بدلاً من ملف خط محدد. بدلاً من إنشاء خط بالاسم، يحدد المطور العائلة والنمط والحجم والسمات الاختيارية، ويقوم النظام باختيار أفضل تطابق. هذا النهج ضروري للطباعة المتكيفة: يمكن لنفس الواصف العمل عبر إصدارات iOS المختلفة حيث تختلف مجموعة الخطوط المتاحة. وفقاً لإرشادات واجهة المستخدم البشرية لنظام iOS، فإن مطابقة الخطوط عبر الواصفات هي الطريقة الموصى بها للعمل مع الخطوط الديناميكية.
بدون Font Descriptor، سيتعين على المطورين التحقق من توفر كل خط بالاسم وتحديد خيارات الاحتياطي يدوياً. يقوم الواصف بأتمتة هذه العملية: يحتوي على مصفوفة توافق للأنماط (عادي، عريض، مائل، عريض مائل) وعند عدم وجود تطابق تام، يقوم بإرجاع أقرب نمط متاح. المطابقة النظامية تعمل على مستوى Core Text وهي متاحة على كل من iOS و macOS من خلال واجهة برمجة التطبيقات الموحدة NSFontDescriptor.
تُستخدم الواصفات أيضاً للخطوط المخصصة — المحملة عبر Info.plist أو المضافة يدوياً. إذا كان الخط مسجلاً في النظام، يتم إنشاء واصفه بنفس الطريقة تماماً كخط النظام. ملاحظة عبر المنصات: مفهوم الواصف موجود أيضاً في Android عبر Typeface.Builder، لكن تطبيق iOS عبر UIFontDescriptor يوفر سمات أكثر بكثير — أكثر من 20 مقارنة بـ 5 في Android.
UIFontDescriptor يحتوي على سمات مجمعة في قاموس fontAttributes من النوع [UIFontDescriptor.AttributeName: Any]. تشمل السمات الرئيسية عائلة الخط والاسم والحجم والخصائص ومصفوفة التحويل والحجم البصري ونمط النص. وفقاً لجلسة Apple WWDC 2019 رقم 227، فإن استخدام أنماط النص — Dynamic Type — إلزامي للتطبيقات المتوافقة مع إمكانية الوصول.
سمة traits هي قاموس يحتوي على خصائص رمزية: الوزن (UIFontWeightTrait)، الميل (UIFontSlantTrait)، العرض (UIFontWidthTrait) وغيرها. تُستخدم هذه القيم بواسطة مُطابق الخط لاختيار النمط. على سبيل المثال، UIFontWeightTrait بقيمة 0.0 — نمط عادي، 0.3 — عريض. يقوم النظام تلقائياً بتعيين القيم الرقمية إلى المتغيرات المتاحة للخط.
تشمل السمات الإضافية featureSettings لميزات OpenType (الربط، الكيرنينغ، النسب الرقمية)، و visibleName للعرض للمستخدم، و matrix للتحويلات الأفينية للخط، و cascadeList لقوائم الاحتياطي المتتالية. تغطي القائمة الكاملة للسمات جميع سيناريوهات الطباعة تقريباً في iOS و macOS.
| السمة | النوع | الوصف |
|---|---|---|
| UIFontDescriptorFamily | String | عائلة الخط (SF Pro, Helvetica Neue) |
| UIFontDescriptorName | String | الاسم الكامل للخط (HelveticaNeue-Bold) |
| UIFontDescriptorSize | NSNumber | حجم الخط بالنقاط |
| UIFontDescriptorMatrix | NSValue | مصفوفة التحويل الأفيني |
| UIFontDescriptorTraits | [String: Any] | خصائص النمط الرمزية |
| UIFontDescriptorTextStyle | String | نمط Dynamic Type (headline, body, caption) |
الطريقة الأساسية للعمل مع Font Descriptor في iOS هي إنشاء واصف ثم توليد UIFont منه. هذا هو النهج المفضل عندما تحتاج إلى خط بخصائص محددة دون معرفة الاسم الدقيق. تتكون العملية من خطوتين: إنشاء UIFontDescriptor عبر المُهيئ واستدعاء طريقة font(withSize:) على الواصف.
import UIKit
// إنشاء واصف خط للعائلة
let descriptor = UIFontDescriptor.init(
fontAttributes: [
.family: "SF Pro",
.traits: [
.weight: UIFont.Weight.bold
]
]
)
// توليد UIFont من الواصف
let font = descriptor.font(withSize: 17)
يضمن هذا النهج أن النظام يختار أفضل تطابق للنمط العريض لـ SF Pro على الجهاز الحالي. الميزة الرئيسية — الكود لا يعتمد على إصدار iOS: على iOS 13 سيتم استخدام SF Pro، على الإصدارات الأقدم — Helvetica Neue أو خط النظام الافتراضي.
لإنشاء خط بحجم ديناميكي، استخدم المُهيئ مع نمط النص والمقياس. يقوم Dynamic Type تلقائياً بضبط الحجم وفقاً لإعدادات المستخدم:
// واصف Dynamic Type
let bodyDescriptor = UIFontDescriptor
.preferredFontDescriptor(withTextStyle: .body)
// جعل الخط عريضاً
let boldDescriptor = bodyDescriptor.withSymbolicTraits([.traitBold])
// توليد UIFont مع الحفاظ على الحجم الديناميكي
let boldBodyFont = UIFont(
descriptor: boldDescriptor!,
size: bodyDescriptor.pointSize
)
هام: طريقة withSymbolicTraits تُرجع واصفاً اختيارياً — إذا كان النمط المطلوب غير متاح، تُرجع nil. تحقق دائماً من الاختياري قبل الاستخدام.
يدعم Font Descriptor نموذجاً غير قابل للتغيير — كل طريقة تعديل تُرجع واصفاً جديداً بالسمة المعدلة. يتبع هذا دلالات القيمة ويجعل الكود قابلاً للتوقع: الواصف الأصلي لا يتغير أبداً. طرق التعديل الرئيسية هي: addingAttributes لإضافة السمات، withFace لتغيير النمط، withSize لتغيير الحجم، withMatrix للتحويل الأفيني.
طريقة addingAttributes هي الأكثر مرونة. تأخذ قاموساً من السمات وتُرجع واصفاً جديداً. عند تطابق المفاتيح، تحل القيم الجديدة محل القديمة. يتيح ذلك دمج التغييرات: إضافة الوزن، تغيير الحجم، وتفعيل الربط في استدعاء واحد. وفقاً لسؤال Apple التقني QA1682، فإن addingAttributes هي الطريقة الموصى بها للتعديل الجماعي عبر الامتداد.
حالة استخدام عملية: إنشاء خط للنص أحادي المسافة في محرر أكواد. يأخذ المطور الواصف أحادي المسافة للنظام، يضيف وزناً مخفضاً للخطوط الرفيعة ويزيد التباعد بين الأحرف عبر featureSettings. يوفر هذا كوداً أكثر قابلية للقراءة دون تحميل خط منفصل.
let monoDescriptor = UIFontDescriptor.monospacedDigitFontDescriptor()
// إضافة سمات مخصصة
let customDescriptor = monoDescriptor.addingAttributes([
.size: 14,
.traits: [
.weight: UIFont.Weight.medium
]
])
let monoFont = UIFont(
descriptor: customDescriptor,
size: 14
)
القيود: لا يمكن تغيير جميع السمات بعد إنشاء الواصف. على سبيل المثال، يتم تعيين عائلة الخط مرة واحدة أثناء التهيئة. إذا كنت بحاجة إلى تغيير العائلة، قم بإنشاء واصف جديد. هذا مرتبط بهندسة Core Text، حيث يرتبط الواصف بمورد خط محدد.
مطابقة الخطوط هي ميزة رئيسية لـ Font Descriptor تختار تلقائياً أفضل تطابق للسمات المطلوبة بين الخطوط المثبتة. تتضمن العملية ثلاث مراحل: التصفية (استبعاد الخطوط غير المتوافقة)، الترتيب (الفرز حسب درجة التطابق)، والاختيار (إرجاع أفضل نتيجة). يتم تنفيذ المطابقة على مستوى Core Text — الإطار الأساسي لجميع طباعة iOS.
للعثور على جميع الخطوط المطابقة لواصف، استخدم طريقة matchingFontDescriptors. تُرجع مصفوفة من الواصفات مرتبة حسب الصلة. يمكن للمطور اختيار التطابق التام (العنصر الأول) أو التنقل بين الخيارات لمنطق مخصص. وفقاً لدليل معالجة الخطوط من Apple، هذه هي الطريقة الوحيدة للحصول على قائمة بالأنماط المتاحة لعائلة محددة دون تعدادها بالاسم.
حالة استخدام: عند اختيار خط في واجهة إعدادات النص. يختار المستخدم عائلة، ويستخدم التطبيق matchingFontDescriptors للحصول على جميع الأنماط المتاحة وعرضها في منتقي. بدون المطابقة، سيتعين على المطورين ترميز قائمة من الخيارات التي تتغير بين إصدارات iOS.
let searchDescriptor = UIFontDescriptor.init(
fontAttributes: [.family: "SF Mono"]
)
// الحصول على جميع الأنماط المتاحة
let matchingDescriptors = searchDescriptor
.matchingFontDescriptors(withMandatoryKeys: nil)
for descriptor in matchingDescriptors {
print(descriptor.object(forKey: .visibleName) ?? "unnamed")
}
المفاتيح الإلزامية — معلمة تقيد البحث. إذا حددت [.family]، تُرجع المطابقة جميع خطوط العائلة المحددة. إذا حددت [.family, .traits] — فقط تلك التي تطابق العائلة والنمط معاً. استخدام المفاتيح الإلزامية يسرع المطابقة عند البحث عن مجموعة فرعية من الخطوط.
الأداء: المطابقة هي عملية متزامنة تستغرق من 0.5 إلى 5 مللي ثانية على iOS. لبحث واحد، هذا غير ملحوظ، ولكن للتكرار الجماعي على الواصفات (على سبيل المثال، في منتقي يحتوي على أكثر من 50 خطاً)، يُوصى بتخزين النتائج مؤقتاً. توصي Apple بإجراء المطابقة مرة واحدة عند تحميل الشاشة وحفظ مصفوفة الواصفات.
Core Text هو إطار منخفض المستوى يعتمد على C للعمل مع الطباعة على iOS و macOS. نظيره لـ UIFontDescriptor هو CTFontDescriptor، الذي يوفر نفس الإمكانيات على مستوى Core Foundation. يُستخدم CTFontDescriptor في واجهات برمجة تطبيقات Core Text لإنشاء الخطوط وقياس النص وعرض الطباعة المعقدة. UIFontDescriptor هو في الأساس غلاف Objective-C حول CTFontDescriptor مع مجموعة موسعة من السمات.
يسمح الجسر toll-free بين UIFontDescriptor و CTFontDescriptor بتمرير الواصفات بين UIKit و Core Text بدون تحويل. هذا أمر بالغ الأهمية للتطبيقات التي تستخدم عرض نص مخصص — على سبيل المثال، محررات النص القائمة على TextKit أو محررات الأكواد مع تمييز الصياغة. مثال: CTFontDescriptorCreateCopyWithAttribute تنشئ نسخة من الواصف مع سمة مضافة — مماثلة لـ addingAttributes من UIFontDescriptor.
السمة الرئيسية kCTFontURLAttribute في CTFontDescriptor تحتوي على رابط ملف الخط. يتيح هذا تحديد ما إذا كان الخط نظامياً أم مخصصاً. للخطوط المخصصة، يشير الرابط إلى ملف الخط (.ttf أو .otf)، للخطوط النظامية — إلى دليل خطوط النظام. البيانات عبر الواصف هي للقراءة فقط؛ لا يُدعم تعديل ملف الخط عبر الرابط.
للطباعة المتقدمة — الربط المخصص، الاستبدالات السياقية، الأشكال البديلة — استخدم CTFontDescriptorCopyAttribute مع المفتاح kCTFontFeatureSettingsAttribute. تحتوي هذه السمة على مصفوفة من قواميس ميزات OpenType التي يمكن إضافتها عبر الواصف. وفقاً لدليل برمجة Core Text من Apple، فإن الجمع بين UIFontDescriptor و Core Text يمنح تحكماً كاملاً في طباعة التطبيق.
الأسئلة الشائعة
UIFont هو خط جاهز للاستخدام يعرض النص. Font Descriptor هو وصف للخط — مجموعة سمات يمكن من خلالها إنشاء UIFont. يمكن لواصف واحد إنتاج العديد من UIFont بأحجام مختلفة.
نعم. إذا كان الخط مسجلاً في النظام (عبر Info.plist أو Core Graphics)، يتم إنشاء واصفه حسب العائلة أو حسب الاسم تماماً كما هو الحال لخطوط النظام. تعمل المطابقة لأي خطوط مسجلة.
استخدم descriptor.object(forKey: .visibleName) للحصول على الاسم المعروض، أو descriptor.postscriptName لاسم PostScript. يُستخدم اسم PostScript عند إنشاء خط عبر UIFont(name:size:).
القائمة المتتالية هي مصفوفة من الواصفات المتداخلة التي تعمل كخطوط احتياطية. إذا كان الخط الأساسي لا يحتوي على الحرف المطلوب، يتحقق النظام بشكل تسلسلي من الخطوط في القائمة المتتالية. تُستخدم لدعم الرموز التعبيرية وأحرف CJK.
نعم. يدعم SwiftUI Font Descriptor عبر Font(descriptor:size:). يقبل غلاف SwiftUI UIFontDescriptor وينشئ خط SwiftUI، محافظاً على جميع سمات الواصف — الكيرنينغ والربط والنمط.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.
اقرأ أيضًا