UIFont و CTFont — کلاسهایی برای کار با فونتها در iOS هستند: UIFont از UIKit برای پیکربندی سطح بالای متن در UILabel و UITextView، CTFont از Core Text برای رندر سطح پایین با کنترل کامل بر گلیفها و متریکها. طبق Apple Developer Documentation، UIFont در 90% کامپوننتهای استاندارد UI استفاده میشود، در حالی که CTFont در موتورهای متنی سفارشی و ویرایشگرها به کار میرود. هر دو کلاس یک فونت را اما در سطوح مختلف انتزاع نمایش میدهند.
نکات اصلی
UIFont — کلاس UIKit است که فونت را برای نمایش متن در کامپوننتهای UI نمایش میدهد: UILabel، UITextView، UITextField. این کلاس رابط سادهای برای دریافت فونتهای سیستمی و سفارشی با تعیین اندازه، وزن و سبک فراهم میکند. UIFont اجازه مدیریت مستقیم کرنینگ، لیگاتورها و ویژگیهای OpenType را نمیدهد — برای این کار از Core Text استفاده میشود.
CTFont — نوع Core Text (CTFontRef) است که دسترسی سطح پایین به دادههای فونت را فراهم میکند. CTFont مستقیماً با Core Graphics برای رندر کار میکند، از تمام قابلیتهای OpenType و TrueType از جمله گلیفهای جایگزین، لیگاتورها و فونتهای متغیر پشتیبانی میکند. CTFont در داخل UIKit برای رندر UIFont استفاده میشود، اما برای ترسیم سفارشی نیز مستقیماً در دسترس است.
UIFont و CTFont از toll-free bridging — تبدیل بین انواع بدون هزینه اضافی پشتیبانی میکنند. تبدیل (cast) UIFont as CTFont یا CTFont as UIFont در Swift و Objective-C امکانپذیر است. این اجازه میدهد از API سطح بالای UIKit برای پیکربندی و Core Text سطح پایین برای رندر بدون کپی کردن دادههای فونت استفاده کنید.
هر دو کلاس از UIFontDescriptor (UIKit) / CTFontDescriptor (Core Text) برای توصیف ویژگیهای فونت استفاده میکنند: نام، اندازه، وزن، سبک، ماتریس تبدیل. Descriptor یک فرهنگ لغت از ویژگیها است که میتوان آن را تغییر داد و فونتهای جدیدی بر اساس فونتهای موجود ایجاد کرد. مثلاً traitItalic را به descriptor اضافه کرده و نسخه ایتالیک همان فونت را دریافت کنید.
UIFont چندین متد کارخانهای برای ایجاد فونتها فراهم میکند. systemFont(ofSize:) فونت سیستمی San Francisco (iOS) یا Helvetica (نسخههای قدیمی) را برمیگرداند. boldSystemFont، italicSystemFont — انواع با حروف. preferredFont(forTextStyle:) فونت Dynamic Type را برای سبک داده شده برمیگرداند: .headline، .body، .caption1، .footnote. این فونتها هنگام تغییر تنظیمات اندازه متن در سیستم به طور خودکار مقیاس میشوند.
برای بارگذاری فونتهای سفارشی از UIFont(name:size:) با نام PostScript فونت استفاده میشود. فونت باید از قبل به Info.plist اضافه شده و در bundle برنامه گنجانده شود. به گفته Apple، توصیه میشود برای تمام کامپوننتهای استاندارد UI از UIFont استفاده کنید و فقط در صورت نیاز به رندر سفارشی به CTFont مهاجرت کنید.
Dynamic Type — سیستم فونتهای تطبیقی معرفی شده در iOS 7. کاربر اندازه متن ترجیحی خود را در تنظیمات انتخاب میکند — از بسیار کوچک تا بسیار بزرگ. UIFont.preferredFont به طور خودکار فونت با اندازه مناسب را برمیگرداند. برای کار صحیح، تمام UILabelها باید adjustsFontForContentSizeCategory = true داشته باشند. Dynamic Type برای سازگاری با دسترسی اجباری است.
UIFontDescriptor امکان تغییر ویژگیهای فونت را بدون ایجاد نمونه جدید از صفر فراهم میکند. متدهای addingAttributes(_:)، withSymbolicTraits(_:)، withFamily(_:) یک descriptor جدید با پارامترهای تغییر یافته برمیگردانند. این برای دریافت انواع فونت مفید است: افزودن traitBold به فونت سیستمی و دریافت نسخه پررنگ بدون دانستن نام PostScript.
CTFont (CTFontRef) — نوع Core Text برای کار سطح پایین با فونتها است. با توابع CTFontCreateWithName، CTFontCreateWithFontDescriptor، CTFontCreateCopyWithAttributes ایجاد میشود. هر تابع فونتی با واسط، اندازه و ویژگیهای اختیاری مشخص شده برمیگرداند. CTFont در Core Graphics برای رندر متن در UIViewهای سفارشی از طریق drawRect استفاده میشود.
CTFont دسترسی به متریکهایی را فراهم میکند که در UIFont موجود نیستند: CTFontGetGlyphsForCharacters آرایهای از گلیفها برای کاراکترهای داده شده برمیگرداند، CTFontGetAdvancesForGlyphs — عرض هر گلیف، CTFontGetBoundingBox — مرزهای گلیف. این برای ساخت layoutهای متنی سفارشی ضروری است: ستونها، چرخش، جریان.
CTFontGetAscent، CTFontGetDescent، CTFontGetLeading متریکهای عمودی فونت را برمیگردانند. CTFontGetUnitsPerEm — تعداد واحدها در em-square، برای محاسبه نسبتها استفاده میشود. CTFontGetGlyphCount — تعداد کل گلیفها در فونت. این دادهها برای تایپوگرافی چاپی و صفحهبندیهای سفارشی که نیاز به موقعیتیابی دقیق هر کاراکتر دارند، حیاتی هستند.
CTFont از ویژگیهای OpenType پشتیبانی میکند: CTFontCopyFeatures فرهنگ لغت توابع موجود فونت را برمیگرداند (لیگاتورها، کاراکترهای جایگزین، کرنینگ)، CTFontEnableFeature گزینه خاصی را فعال میکند. فونتهای متغیر (Variable Fonts) از طریق CTFontCopyVariation و CTFontCreateCopyWithVariation پیکربندی میشوند و امکان تغییر weight، width و slant را در محدوده پیوسته فراهم میکنند.
ایجاد UIFont در Swift از طریق یکی از متدهای کارخانهای یا مقداردهی مستقیم با نام انجام میشود. رایجترین روش systemFont(ofSize:weight:) برای فونتهای سیستمی یا preferredFont(forTextStyle:) برای Dynamic Type است. برای فونتهای سفارشی از UIFont(name:size:) با ذکر نام PostScript استفاده میشود.
UIFont.systemFont(ofSize:weight:) UIFont.Weight را میپذیرد — از .ultraLight تا .black. این متد فونت سیستمی San Francisco با وزن مربوطه را برمیگرداند. UIFont.monospacedSystemFont، UIFont.monospacedDigitSystemFont فونتهای همعرض را برای کد و اعداد برمیگردانند. تمام فونتهای سیستمی به طور خودکار از Dynamic Type پشتیبانی میکنند.
let regularFont = UIFont.systemFont(ofSize: 16, weight: .regular)
let boldFont = UIFont.systemFont(ofSize: 16, weight: .bold)
let headlineFont = UIFont.preferredFont(forTextStyle: .headline)
let monoFont = UIFont.monospacedSystemFont(ofSize: 14, weight: .regular)
label.font = headlineFont
هر فونت را میتوان مستقیماً به ویژگی font UILabel نسبت داد یا در NSAttributedString از طریق NSFontAttributeName استفاده کرد. فونتهای سیستمی توسط iOS کش میشوند، بنابراین ایجاد مجدد فونت سیستمی هزینه اضافی ندارد.
برای استفاده از فونت سفارشی، فایل TTF یا OTF را به bundle پروژه اضافه کنید و آن را در Info.plist (UIAppFonts) مشخص کنید. نام PostScript فونت را میتوان از طریق UIFont.familyNames و UIFont.fontNames(forFamilyName:) پیدا کرد. پس از ثبت، فونت از طریق UIFont(name:size:) در هر نقطه از برنامه در دسترس است.
// دریافت همه نامهای خانواده فونت
for family in UIFont.familyNames {
let names = UIFont.fontNames(forFamilyName: family)
print("\(خانواده): \(نامها)")
}
// بارگذاری فونت سفارشی
if let customFont = UIFont(name: "MyCustomFont-Regular", size: 18) {
label.font = customFont
}
اگر نام فونت نادرست باشد، UIFont(name:size:) nil برمیگرداند. توصیه میشود تمام نامهای موجود فونتها را از طریق UIFont.familyNames و UIFont.fontNames(forFamilyName:) در زمان دیباگ چاپ کنید تا مطمئن شوید فونت به درستی ثبت شده است.
بارگذاری فونتهای سفارشی به دو روش امکانپذیر است: ثبت استاتیک از طریق Info.plist (UIAppFonts) و ثبت پویا از طریق CTFontManagerRegisterGraphicsFont. روش اول سادهتر است — فونت بلافاصله پس از راهاندازی برنامه در دسترس است. روش دوم برای فونتهایی که از شبکه بارگذاری میشوند یا به صورت درخواستی دانلود میشوند استفاده میشود.
ثبت پویا برای منابع درخواستی مفید است: اگر برنامه حاوی 20+ فونت باشد، نیازی به گنجاندن همه آنها در bundle اولیه نیست، بلکه میتوان در اولین استفاده آنها را دانلود کرد. CTFontManagerRegisterFontsForURLs فونتها را از URLهای مشخص شده ثبت میکند. پس از ثبت، فونت مانند همیشه از طریق UIFont(name:size:) در دسترس است.
برای رندر سفارشی از طریق Core Text از CTFontCreateWithName با نام PostScript فونت استفاده کنید. تفاوت با UIFont این است که CTFont میتواند با ماتریس تبدیل ایجاد شود (CTFontCreateWithNameAndOptions) — برای ایجاد فونتهای تحریف شده: کج کردن، مقیاس در محور X، چرخش. این بدون استفاده از تبدیلهای affine در UIFont در دسترس نیست.
// ایجاد CTFont با ماتریس کج
var matrix = CGAffineTransform(a: 1, b: 0, c: 0.2, d: 1, tx: 0, ty: 0)
let ctFont = CTFontCreateWithName(
"Helvetica" as CFString,
24, &matrix)
// استفاده از toll-free bridging با UIFont
let uiFont = ctFont as UIFont
label.font = uiFont
ماتریس تبدیل امکان ایجاد انواع italic را بدون فایل جداگانه فونت فراهم میکند. پارامتر c (skew) به حروف کجی اضافه میکند. ماتریس همچنین امکان مقیاس افقی فونت را فراهم میکند — ایجاد انواع فشرده یا گسترده از همان فونت.
تفاوت اصلی بین UIFont و CTFont سطح انتزاع است. UIFont API سادهای برای وظایف رایج فراهم میکند: دریافت فونت سیستمی، تغییر اندازه، اعمال به UILabel. CTFont کنترل کامل بر فونت را ارائه میدهد: دسترسی به گلیفها، متریکها، جداول OpenType و محورهای متغیر. انتخاب بستگی به وظیفه دارد.
| ویژگی | UIFont | CTFont |
|---|---|---|
| فریمورک | UIKit | Core Text |
| ایجاد | systemFont / preferredFont / initWithName | CTFontCreateWithName / CTFontCreateWithDescriptor |
| دسترسی به گلیفها | خیر | CTFontGetGlyphsForCharacters |
| ویژگیهای OpenType | محدود (UIFontDescriptor) | دسترسی کامل |
| فونتهای متغیر | از طریق UIFontDescriptor | CTFontCopyVariation / CreateCopyWithVariation |
| رندر | خودکار در کامپوننتهای UI | Core Graphics، سفارشی |
برای 95% وظایف توسعه iOS UIFont کافی است. Core Text با CTFont در ایجاد ویرایشگرهای متن، تولیدکنندگان PDF، کتابهای با صفحهبندی تایپوگرافی یا برنامههای با نمایش سفارشی زبانهای نادر توجیه میشود.
کار با فونتها در iOS نیاز به در نظر گرفتن عملکرد دارد. هر فونت منحصر به فرد در اولین استفاده در حافظه بارگذاری میشود و منابع را اشغال میکند. فونتهای سیستمی San Francisco از پیش بارگذاری شدهاند و هزینه اضافی ایجاد نمیکنند. فونتهای سفارشی از فایل بارگذاری میشوند و پس از اولین بارگذاری توسط سیستم کش میشوند.
توصیه میشود تعداد فونتهای منحصر به فرد در برنامه را به 3-5 خانواده محدود کنید. هر فونت از 50 کیلوبایت تا 2 مگابایت در حافظه اشغال میکند. استفاده از وزنهای مختلف یک خانواده (regular، bold، medium) کارآمدتر از بارگذاری چند خانواده مختلف است.
سیستم نمونههای ایجاد شده UIFont را کش میکند، بنابراین فراخوانیهای مکرر UIFont.systemFont(ofSize: 16, weight: .regular) شیء جدیدی ایجاد نمیکنند. با این حال، UIFont(name:size:) برای فونتهای سفارشی همیشه کش نمیشود — توصیه میشود فونتهای پراستفاده را در ویژگیهای استاتیک یا کش NSCache ذخیره کنید تا از بارگذاری مجدد از فایل جلوگیری شود.
در هنگام ثبت پویای فونتها از طریق CTFontManagerRegisterGraphicsFont، فرآیند میتواند ناهمگام باشد اگر فایل فونت از شبکه دانلود شود. در این حالت، UILabel یا UITextView باید فونت سیستمی پشتیبان را تا زمان تکمیل بارگذاری نمایش دهند. پس از ثبت، فونت در دسترس میشود و صفحه به طور خودکار نمایش متن را بهروز میکند.
سوالات متداول
بله، UIFont و CTFont از toll-free bridging پشتیبانی میکنند. تبدیل با یک کست ساده انجام میشود: UIFont as CTFont یا CTFont as UIFont. هیچ هزینه اضافی یا کپی دادهای رخ نمیدهد — هر دو کلاس به یک شیء فونت در حافظه اشاره میکنند.
برای تمام کامپوننتهای UI از UIFont استفاده کنید. این کلاس برای UIKit بهینه شده، از Dynamic Type پشتیبانی میکند و با تغییر تنظیمات سیستم به درستی مقیاس میشود. CTFont فقط برای رندر سفارشی از طریق Core Graphics یا در صورت نیاز به دسترسی به متریکهای سطح پایین فونت توجیه میشود.
از UIFont.familyNames برای لیست خانوادهها و UIFont.fontNames(forFamilyName:) برای نامهای PostScript استفاده کنید. این کد را در حالت دیباگ فراخوانی کنید و فونت مورد نظر را پیدا کنید. نام PostScript معمولاً شامل نام خانواده و حروف است: “SFProText-Regular”، “HelveticaNeue-Bold”.
بله، از طریق UIFontDescriptor میتوان محورهای متغیر را پیکربندی کرد: weight، width، slant. با این حال، API UIFont برای فونتهای متغیر در مقایسه با CTFontCopyVariation محدود است. برای کنترل کامل بر محورهای متغیر از Core Text و CTFontCreateCopyWithVariation استفاده کنید.
یک فرهنگ لغت استاتیک یا NSCache با کلید ترکیبی از نام و اندازه ایجاد کنید. برای فونتهای سیستمی، iOS نمونهها را به طور خودکار کش میکند، اما برای فونتهای سفارشی ایجاد شده از طریق UIFont(name:size:)، توصیه میشود اشیاء را در کش برنامه ذخیره کنید تا از بارگذاری مجدد از فایل TTF جلوگیری شود.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید