Font Descriptor — شیئی UIFontDescriptor در iOS و NSFontDescriptor در macOS است که کلیه اطلاعات قلم را محاصره میکند: خانواده، نمای قلم، اندازه، فاصله حروف، فاصله خطوط و ویژگیهای تایپوگرافی. به جای ساخت مستقیم قلم از طریق UIFont(name:size:)، توسعهدهنده ویژگیهای مورد نظر را از طریق توصیفکننده توصیف میکند و سیستم بهترین تطبیق را از قلمهای موجود انتخاب میکند. به استناد به Apple Developer Documentation، UIFontDescriptor از بیش از 20 ویژگی قلم پشتیبانی میکند و در تمامی چارچوبهای تایپوگرافی iOS — از UIKit گرفته تا Core Text و SwiftUI — استفاده میشود.
امور اصلی
Font Descriptor — شیئی است که ویژگیهای قلم را به صورت مجموعهای از جفت کلید-مقدار توصیف میکند، نه به صورت یک فایل قلم مشخص. به جای ساخت قلم با نام، توسعهدهنده خانواده، نمای قلم، اندازه و ویژگیهای اختیاری را مشخص میکند و سیستم بهترین تطبیق را انتخاب میکند. چنین رویکردی برای تایپوگرافی سازگار حیاتی است: همان توصیفکننده میتواند روی نسخههای مختلف iOS کار کند که دسته قلمهای موجود متفاوت است. به استناد به iOS Human Interface Guidelines، تطبیق قلم از طریق توصیفکنندهها روش توصیهشده برای کار با قلمهای پویا است.
بدون Font Descriptor، توسعهدهنده مجبور بود دسترسی هر قلم را با نام بررسی کند و گزینههای افتاده را دستی مشخص کند. توصیفکننده این فرآیند را خودکار میکند: آن شامل ماتریس سازگاری نمای قلم است — عادی، ضخیم، ایتالیک، ضخیم ایتالیک — و در صورت عدم وجود تطبیق دقیق، نزدیکترین گزینه موجود را برمیگرداند. تطبیق سیستمی در سطح Core Text کار میکند و هم در iOS و هم در macOS از طریق یک API واحد NSFontDescriptor در دسترس است.
توصیفکنندهها همچنین برای قلمهای سفارشی — بارگذاریشده از طریق Info.plist یا افزوده شده دستی — استفاده میشوند. اگر قلمی در سیستم ثبت شده باشد، توصیفکننده آن دقیقاً مانند قلم سیستمی ایجاد میشود. یادداشت چندسطحی: مفهوم توصیفکننده در Android نیز از طریق Typeface.Builder وجود دارد، اما پیادهسازی iOS از طریق UIFontDescriptor به مراتب ویژگیهای بیشتری میدهد — بیش از 20 ویژگی در مقابل 5 در Android.
UIFontDescriptor حاوی اتریبوتهایی است که در یک فرهنگ fontAttributes از نوع [UIFontDescriptor.AttributeName: Any] گروهبندی شدهاند. اتریبوتهای کلیدی شامل خانواده قلم (family)، نام (name)، اندازه (size)، ویژگیهای قلم (traits)، ماتریس تبدیل (matrix)، اندازه نوری (opticalSize) و سبک متن (textStyle) هستند. به استناد به Apple WWDC 2019 Session 227، استفاده از سبکهای متن — Dynamic Type — برای برنامههای منطبق با accessibility ضروری است.
اتریبوت 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 Technical Q&A QA1682، addingAttributes روش توصیهشده برای تغییر گروهی از طریق افزایش است.
کاربرد عملی: ایجاد قلم برای متن همعرض در ویرایشگر کد. توسعهدهنده توصیفکننده monospace سیستمی را برمیدارد، وزن کاهشیافته برای خطوط نازک اضافه میکند و فاصله حروف را از طریق featureSettings افزایش میدهد. این کار کدی خواناتر بدون بارگذاری قلم جداگانه ایجاد میکند.
let monoDescriptor = UIFontDescriptor.monospacedDigitFontDescriptor()
// اضافه کردن اتریبوتهای سفارشی
let customDescriptor = monoDescriptor.addingAttributes([
.size: 14,
.traits: [
.weight: UIFont.Weight.medium
]
])
let monoFont = UIFont(
descriptor: customDescriptor,
size: 14
)
محدودیت: همه اتریبوتها را نمیتوان پس از ایجاد توصیفکننده تغییر داد. به عنوان مثال، خانواده قلم (family) یک بار در زمان سازنده تعیین میشود. اگر نیاز به تغییر خانواده دارید، یک توصیفکننده جدید ایجاد کنید. این به معماری Core Text مربوط است که در آن توصیفکننده به یک منبع قلم خاص متصل است.
تطبیق قلم — ویژگی کلیدی Font Descriptor است که به طور خودکار بهترین تطبیق با اتریبوتهای مورد نظر را از میان قلمهای نصبشده انتخاب میکند. فرآیند شامل سه مرحله است: فیلتر (حذف قلمهای ناسازگار)، رتبهبندی (مرتبسازی بر اساس درجه تطبیق) و انتخاب (بازگرداندن بهترین نتیجه). تطبیق در سطح Core Text انجام میشود — چارچوبی که در پایه تمامی تایپوگرافی iOS قرار دارد.
برای جستجوی همه قلمهایی که با توصیفکننده مطابقت دارند، از روش matchingFontDescriptors استفاده میشود. آن یک مجموعه از توصیفکنندهها را مرتب بر اساس مربوطیت بازمیگرداند. توسعهدهنده میتواند تطبیق دقیق (عنصر اول) را انتخاب کند یا برای منطق سفارشی گزینهها را مرور کند. به استناد به Apple Font Handling Guide، این تنها راه دریافت لیست نمای قلمهای موجود برای یک خانواده خاص بدون شمارش به نام است.
سناریو استفاده: در زمان انتخاب قلم در رابط تنظیمات متن. کاربر یک خانواده را انتخاب میکند و برنامه از طریق 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")
}
Mandatory keys — پارامتری که جستجو را محدود میکند. اگر [.family] مشخص شود، تطبیق همه قلمهای خانواده مشخص را بازمیگرداند. اگر [.family, .traits] مشخص شود — فقط آنهایی که هم با خانواده و هم با نمای قلم مطابقت دارند. استفاده از mandatory keys تطبیق را در جستجوی زیرمجموعه قلمها سریعتر میکند.
کارایی: تطبیق یک عملیات همزمان است که در iOS حدود 0.5 تا 5 میلیثانیه طول میکشد. برای یک جستجوی تکی این قابل توجه نیست، اما در کارورد انبوه توصیفکنندهها (مثل در انتخابگری با 50+ قلم) ذخیرهسازی نتایج توصیه میشود. Apple توصیه میکند تطبیق را یک بار هنگام بارگذاری صفحه انجام داده و مجموعه توصیفکنندهها را ذخیره کنید.
Core Text — چارچوبی C سطح پایین برای کار با تایپوگرافی در iOS و macOS است. معادل UIFontDescriptor آن — CTFontDescriptor است که همان امکانات را در سطح Core Foundation فراهم میکند. CTFontDescriptor در Core Text API برای ایجاد قلمها، اندازهگیری متن و رندر تایپوگرافی پیچیده استفاده میشود. UIFontDescriptor در حقیقت یک پوشش Objective-C بر روی CTFontDescriptor با مجموعه اتریبوتهای گسترده است.
Toll-free bridging بین UIFontDescriptor و CTFontDescriptor امکان انتقال توصیفکنندهها را بین UIKit و Core Text بدون تبدیل فراهم میکند. این برای برنامههایی که از رندرینگ سفارشی متن استفاده میکنند — مانند ویرایشگرهای متنی بر پایه TextKit یا ویرایشگرهای کد با هایلایت سنتکس — حیاتی است. مثال: CTFontDescriptorCreateCopyWithAttribute یک کپی از توصیفکننده با اتریبوت اضافه شده ایجاد میکند — معادل addingAttributes از UIFontDescriptor.
اتریبوت کلیدی kCTFontURLAttribute در CTFontDescriptor شامل URL فایل قلم است. این امکان تشخیص سیستمی بودن یا سفارشی بودن قلم را فراهم میکند. برای قلمهای سفارشی، URL به فایل قلم (.ttf یا .otf) اشاره میکند، برای سیستمی — به پوشه سیستمی قلمها. اطلاعات از طریق توصیفکننده فقط خواندنی است؛ تغییر فایل قلم از طریق URL پشتیبانی نمیشود.
برای تایپوگرافی پیشرفته — لیگاتورهای سفارشی، جایگزینیهای کنتکستی، گلیفهای جایگزین — از CTFontDescriptorCopyAttribute با کلید kCTFontFeatureSettingsAttribute استفاده میشود. این اتریبوت شامل مجموعهای از فرهنگهای ویژگیهای OpenType است که میتوان از طریق توصیفکننده اضافه کرد. به استناد به Apple Core Text Programming Guide، ترکیب UIFontDescriptor با Core Text کنترل کاملی بر تایپوگرافی برنامه میدهد.
سوالات متداول
UIFont — یک قلم آماده برای استفاده است که متن را رندر میکند. Font Descriptor — توصیف قلم، مجموعهای از اتریبوتهاست که از آنها میتوان UIFont ایجاد کرد. یک توصیفکننده میتواند چندین UIFont با اندازههای مختلف ایجاد کند.
بله. اگر قلمی در سیستم ثبت شده باشد (از طریق Info.plist یا Core Graphics)، توصیفکننده آن از طریق خانواده یا نام دقیقاً مانند قلمهای سیستمی ایجاد میشود. تطبیق برای هر قلم ثبتشده کار میکند.
از descriptor.object(forKey: .visibleName) برای دریافت نام قابل نمایش یا descriptor.postscriptName برای نام PostScript استفاده کنید. نام PostScript در زمان ایجاد قلم از طریق UIFont(name:size:) استفاده میشود.
Cascade list — مجموعهای از توصیفکنندههای تودرتو است که به عنوان قلمهای افتاده عمل میکنند. اگر قلم اصلی شامل علامت مورد نظر نباشد، سیستم به ترتیب قلمهای موجود در cascade list را بررسی میکند. برای پشتیبانی از اموجی و علائم CJK استفاده میشود.
بله. SwiftUI از Font Descriptor از طریق Font(descriptor:size:) پشتیبانی میکند. پوشش SwiftUI یک UIFontDescriptor میپذیرد و یک قلم SwiftUI ایجاد میکند و همه اتریبوتهای توصیفکننده را حفظ میکند — کرنینگ، لیگاتورها و نمای قلم.
نتیجهگیری
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید