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 — конверсия между типове без допълнителни разходи. Кастингът UIFont as CTFont или CTFont as UIFont е възможен в Swift и Objective-C. Това позволява използването на високонивовия UIKit API за конфигуриране и нисконивовия Core Text за визуализиране, без копиране на данните на шрифта.
И двете класове използват UIFontDescriptor (UIKit) / CTFontDescriptor (Core Text) за описание на характеристиките на шрифта: име, размер, тегло, стил, матрица на трансформация. Дескрипторът е речник на атрибути, който може да бъде модифициран и да създава нови шрифтове на базата на съществуващи. Например, добавете traitItalic към дескриптор и получете курсивна версия на същия шрифт.
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 се препоръчва използването на UIFont за всички стандартни UI компоненти и преминаване към CTFont само когато се налага персонализирано визуализиране.
Dynamic Type — адаптивна система за шрифтове, въведена в iOS 7. Потребителят избира предпочитания размер на текста в Настройки — от много малък до много голям. UIFont.preferredFont автоматично върща шрифт с подходящ размер. За правилна работа всички UILabel трябва да имат adjustsFontForContentSizeCategory = true. Dynamic Type е задължителен за съвместимост с достъпността.
UIFontDescriptor позволява модифициране на атрибутите на шрифта, без да създавате нов екземпляр от нула. Методите addingAttributes(_:), withSymbolicTraits(_:), withFamily(_:) върщат нов дескриптор с променени параметри. Това е удобно за получаване на варианти на шрифт: добавете 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("\(family): \(names)")
}
// Заредете персонализиран шрифт
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, завъртане. Това не е достъпно в 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 |
|---|---|---|
| Framework | 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 KB до 2 MB в паметта. Използването на различни тегла от едно семейство (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. Въпреки това, UIFont API за вариабилни шрифтове е ограничен в сравнение с CTFontCopyVariation. За пълен контрол над вариабилните оси използвайте Core Text и CTFontCreateCopyWithVariation.
Създайте статичен речник или NSCache с ключ от комбинацията на името и размера. За системните шрифтове, iOS кешира екземплярите автоматично, но за персонализирани шрифтове, създадени чрез UIFont(name:size:), се препоръчва запазване на обектите в кеша на приложението, за да се избегне повторно зареждане от TTF файла.
Обобщение
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също