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. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође