UIFont e CTFont sono classi per lavorare con i font in iOS: UIFont di UIKit per la configurazione del testo ad alto livello in UILabel e UITextView, CTFont di Core Text per il rendering a basso livello con controllo completo su glifi e metriche. Secondo Apple Developer Documentation, UIFont viene utilizzato nel 90% dei componenti UI standard, mentre CTFont viene utilizzato in motori di testo personalizzati ed editor. Entrambe le classi rappresentano lo stesso font ma a diversi livelli di astrazione.
Punti chiave
UIFont è una classe UIKit che rappresenta un font per visualizzare testo nei componenti UI: UILabel, UITextView, UITextField. Fornisce un'interfaccia semplice per ottenere font di sistema e personalizzati con dimensione, peso e stile specificati. UIFont non consente il controllo diretto su kerning, legature e funzionalità OpenType — per questo viene utilizzato Core Text.
CTFont è un tipo Core Text (CTFontRef) che fornisce accesso a basso livello ai dati del font. CTFont lavora direttamente con Core Graphics per il rendering, supporta tutte le funzionalità OpenType e TrueType, inclusi glifi alternativi, legature e font variabili. CTFont viene utilizzato internamente da UIKit per il rendering di UIFont, ma è anche disponibile direttamente per il disegno personalizzato.
UIFont e CTFont supportano il Toll-Free Bridging — conversione tra tipi senza costi aggiuntivi. Il casting UIFont as CTFont o CTFont as UIFont è possibile in Swift e Objective-C. Ciò consente di utilizzare l'API di alto livello di UIKit per la configurazione e Core Text di basso livello per il rendering senza copiare i dati del font.
Entrambe le classi utilizzano UIFontDescriptor (UIKit) / CTFontDescriptor (Core Text) per descrivere le caratteristiche del font: nome, dimensione, peso, stile, matrice di trasformazione. Un descrittore è un dizionario di attributi che può essere modificato per creare nuovi font basati su quelli esistenti. Ad esempio, aggiungere traitItalic a un descrittore e ottenere una versione corsiva dello stesso font.
UIFont fornisce diversi metodi factory per creare font. systemFont(ofSize:) restituisce il font di sistema San Francisco (iOS) o Helvetica (versioni precedenti). boldSystemFont, italicSystemFont — varianti con stili specifici. preferredFont(forTextStyle:) restituisce un font Dynamic Type per lo stile specificato: .headline, .body, .caption1, .footnote. Questi font vengono ridimensionati automaticamente quando le impostazioni della dimensione del testo cambiano nel sistema.
Per caricare font personalizzati, si utilizza UIFont(name:size:) con il nome PostScript del font. Il font deve essere prima aggiunto a Info.plist e incluso nel bundle dell'app. Secondo Apple, si consiglia di utilizzare UIFont per tutti i componenti UI standard e passare a CTFont solo quando è necessario il rendering personalizzato.
Dynamic Type è un sistema di font adattivi introdotto in iOS 7. L'utente seleziona la dimensione del testo preferita in Impostazioni — da extra piccola a extra grande. UIFont.preferredFont restituisce automaticamente un font della dimensione appropriata. Per un corretto funzionamento, tutti gli UILabel devono avere adjustsFontForContentSizeCategory = true. Dynamic Type è obbligatorio per la conformità all'accessibilità.
UIFontDescriptor consente di modificare gli attributi del font senza creare una nuova istanza da zero. I metodi addingAttributes(_:), withSymbolicTraits(_:), withFamily(_:) restituiscono un nuovo descrittore con parametri modificati. Ciò è comodo per ottenere varianti di font: aggiungere traitBold al font di sistema e ottenere una versione in grassetto senza conoscere il nome PostScript.
CTFont (CTFontRef) è un tipo Core Text per il lavoro a basso livello con i font. Viene creato da CTFontCreateWithName, CTFontCreateWithFontDescriptor, CTFontCreateCopyWithAttributes. Ogni funzione restituisce un font con l'interfaccia, la dimensione e gli attributi opzionali specificati. CTFont viene utilizzato in Core Graphics per il rendering del testo su UIView personalizzati tramite drawRect.
CTFont fornisce accesso a metriche non disponibili in UIFont: CTFontGetGlyphsForCharacters restituisce un array di glifi per i caratteri specificati, CTFontGetAdvancesForGlyphs — la larghezza di ciascun glifo, CTFontGetBoundingBox — i limiti del glifo. Ciò è necessario per costruire layout di testo personalizzati: colonne, rotazione, avvolgimento.
CTFontGetAscent, CTFontGetDescent, CTFontGetLeading restituiscono le metriche verticali del font. CTFontGetUnitsPerEm — numero di unità per em-quadrato, utilizzato per il calcolo delle proporzioni. CTFontGetGlyphCount — numero totale di glifi nel font. Questi dati sono fondamentali per la tipografia da stampa e i layout personalizzati dove è richiesto il posizionamento preciso di ogni carattere.
CTFont supporta le funzionalità OpenType: CTFontCopyFeatures restituisce un dizionario delle funzioni disponibili del font (legature, caratteri alternativi, kerning), CTFontEnableFeature attiva un'opzione specifica. I font variabili vengono configurati tramite CTFontCopyVariation e CTFontCreateCopyWithVariation, consentendo di modificare weight, width e slant in un intervallo continuo.
La creazione di UIFont in Swift avviene tramite uno dei metodi factory o l'inizializzazione diretta per nome. Il modo più comune è systemFont(ofSize:weight:) per i font di sistema o preferredFont(forTextStyle:) per Dynamic Type. Per i font personalizzati, si utilizza UIFont(name:size:) con il nome PostScript specificato.
UIFont.systemFont(ofSize:weight:) accetta UIFont.Weight — da .ultraLight a .black. Questo metodo restituisce il font di sistema San Francisco con il peso corrispondente. UIFont.monospacedSystemFont, UIFont.monospacedDigitSystemFont restituiscono font a spaziatura fissa per codice e numeri. Tutti i font di sistema supportano automaticamente 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
Ogni font può essere assegnato direttamente alla proprietà font di UILabel o utilizzato in NSAttributedString tramite NSFontAttributeName. I font di sistema vengono memorizzati nella cache da iOS, quindi ricreare un font di sistema non comporta overhead.
Per utilizzare un font personalizzato, aggiungere il file TTF o OTF al bundle del progetto e specificarlo in Info.plist (UIAppFonts). Il nome PostScript del font può essere trovato tramite UIFont.familyNames e UIFont.fontNames(forFamilyName:). Dopo la registrazione, il font è disponibile tramite UIFont(name:size:) da qualsiasi punto dell'app.
// Ottenere tutti i nomi delle famiglie di font
for family in UIFont.familyNames {
let names = UIFont.fontNames(forFamilyName: family)
print("\(family): \(names)")
}
// Caricare font personalizzato
if let customFont = UIFont(name: "MyCustomFont-Regular", size: 18) {
label.font = customFont
}
Se il nome del font viene specificato in modo errato, UIFont(name:size:) restituisce nil. Si consiglia di stampare tutti i nomi di font disponibili tramite UIFont.familyNames e UIFont.fontNames(forFamilyName:) durante il debug per assicurarsi che il font sia registrato correttamente.
Il caricamento di font personalizzati è possibile in due modi: registrazione statica tramite Info.plist (UIAppFonts) e registrazione dinamica tramite CTFontManagerRegisterGraphicsFont. Il primo metodo è più semplice — il font è disponibile immediatamente dopo l'avvio dell'app. Il secondo viene utilizzato per font scaricati dalla rete o risorse on-demand.
La registrazione dinamica è utile per le risorse on-demand: se l'app contiene più di 20 font, possono essere tutti esclusi dal bundle iniziale e scaricati al primo utilizzo. CTFontManagerRegisterFontsForURLs registra i font da URL specificati. Dopo la registrazione, il font diventa disponibile tramite UIFont(name:size:) come al solito.
Per il rendering personalizzato tramite Core Text, utilizzare CTFontCreateWithName con il nome PostScript del font. La differenza con UIFont è che CTFont può essere creato con una matrice di trasformazione (CTFontCreateWithNameAndOptions) — per creare font distorti: inclinazione, scalatura sull'asse X, rotazione. Questo non è disponibile in UIFont senza utilizzare trasformazioni affini.
// Creare CTFont con matrice di skew
var matrix = CGAffineTransform(a: 1, b: 0, c: 0.2, d: 1, tx: 0, ty: 0)
let ctFont = CTFontCreateWithName(
"Helvetica" as CFString,
24, &matrix)
// Usare Toll-Free Bridging con UIFont
let uiFont = ctFont as UIFont
label.font = uiFont
La matrice di trasformazione consente di creare varianti corsive senza un file di font separato. Il parametro c (skew) aggiunge inclinazione ai caratteri. La matrice consente anche di scalare il font orizzontalmente — creando varianti condensate o espanse dello stesso font.
La differenza principale tra UIFont e CTFont è il livello di astrazione. UIFont fornisce un'API semplice per attività comuni: ottenere un font di sistema, cambiare dimensione, applicare a UILabel. CTFont fornisce il controllo completo sul font: accesso a glifi, metriche, tabelle OpenType e assi variabili. La scelta dipende dall'attività.
| Caratteristica | UIFont | CTFont |
|---|---|---|
| Framework | UIKit | Core Text |
| Creazione | systemFont / preferredFont / initWithName | CTFontCreateWithName / CTFontCreateWithDescriptor |
| Accesso ai glifi | No | CTFontGetGlyphsForCharacters |
| Funzionalità OpenType | Limitato (UIFontDescriptor) | Accesso completo |
| Font variabili | Tramite UIFontDescriptor | CTFontCopyVariation / CreateCopyWithVariation |
| Rendering | Automatico nei componenti UI | Core Graphics, personalizzato |
Per il 95% delle attività di sviluppo iOS, UIFont è sufficiente. Core Text con CTFont è giustificato quando si creano editor di testo, generatori PDF, libri con impaginazione tipografica o app con rendering personalizzato di lingue rare.
Lavorare con i font in iOS richiede la considerazione delle prestazioni. Ogni font unico viene caricato in memoria al primo accesso e consuma risorse. I font di sistema San Francisco sono precaricati e non creano overhead. I font personalizzati vengono caricati dal file e memorizzati nella cache dal sistema dopo il primo caricamento.
Si consiglia di limitare il numero di font unici in un'app a 3-5 famiglie. Ogni font occupa da 50 KB a 2 MB in memoria. Utilizzare pesi diversi della stessa famiglia (regular, bold, medium) è più efficiente che caricare più famiglie diverse.
Il sistema memorizza nella cache le istanze create di UIFont, quindi le chiamate ripetute a UIFont.systemFont(ofSize: 16, weight: .regular) non creano un nuovo oggetto. Tuttavia, UIFont(name:size:) per i font personalizzati non viene sempre memorizzato nella cache — si consiglia di salvare i font utilizzati frequentemente in proprietà statiche o NSCache per evitare di ricaricare dal file.
Quando si registrano font dinamicamente tramite CTFontManagerRegisterGraphicsFont, il processo può essere asincrono se il file del font viene scaricato dalla rete. In questo caso, UILabel o UITextView dovrebbero visualizzare un font di sistema di fallback fino al completamento del caricamento. Dopo la registrazione, il font diventa disponibile e lo schermo aggiorna automaticamente la visualizzazione del testo.
Domande frequenti
Sì, UIFont e CTFont supportano il Toll-Free Bridging. La conversione viene eseguita mediante semplice casting: UIFont as CTFont o CTFont as UIFont. Non si verifica overhead o copia di dati — entrambe le classi puntano allo stesso oggetto font in memoria.
Per tutti i componenti UI, utilizzare UIFont. È ottimizzato per UIKit, supporta Dynamic Type e si ridimensiona correttamente al variare delle impostazioni di sistema. CTFont è giustificato solo per il rendering personalizzato tramite Core Graphics o quando è necessario l'accesso a metriche di font di basso livello.
Utilizzare UIFont.familyNames per un elenco di famiglie e UIFont.fontNames(forFamilyName:) per i nomi PostScript. Chiamare questo codice in modalità debug e trovare il font desiderato. Il nome PostScript contiene solitamente il nome della famiglia e lo stile: “SFProText-Regular”, “HelveticaNeue-Bold”.
Sì, tramite UIFontDescriptor è possibile configurare gli assi variabili: weight, width, slant. Tuttavia, l'API UIFont per i font variabili è limitata rispetto a CTFontCopyVariation. Per il controllo completo degli assi variabili, utilizzare Core Text e CTFontCreateCopyWithVariation.
Creare un dizionario statico o NSCache con una chiave che combina nome e dimensione. Per i font di sistema, iOS memorizza automaticamente nella cache le istanze, ma per i font personalizzati creati tramite UIFont(name:size:), si consiglia di salvare gli oggetti nella cache dell'app per evitare di ricaricare dal file TTF.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche