Font Descriptor — to obiekt UIFontDescriptor w iOS i NSFontDescriptor w macOS, który hermetyzuje wszystkie metadane czcionki: rodzinę, krój, rozmiar, odstępy między znakami, odstępy między wierszami i atrybuty typograficzne. Zamiast tworzyć czcionkę bezpośrednio przez UIFont(name:size:), programista opisuje pożądane cechy przez deskryptor, a system dobiera najlepsze dopasowanie z dostępnych czcionek. Według Apple Developer Documentation, UIFontDescriptor obsługuje ponad 20 atrybutów czcionki i jest używany we wszystkich frameworkach typografii iOS — od UIKit przez Core Text aż po SwiftUI.
Najważniejsze
Font Descriptor — to obiekt, który opisuje charakterystyki czcionki jako zestaw par klucz-wartość, a nie jako konkretny plik czcionki. Zamiast tworzyć czcionkę po nazwie, programista określa rodzinę, krój, rozmiar i opcjonalne atrybuty, a system dobiera najlepsze dopasowanie. Takie podejście jest kluczowe dla adaptacyjnej typografii: ten sam deskryptor może działać na różnych wersjach iOS, gdzie zestaw dostępnych czcionek się różni. Według iOS Human Interface Guidelines, dopasowanie czcionek przez deskryptory to zalecany sposób pracy z dynamicznymi czcionkami.
Bez Font Descriptor programista musiałby sprawdzać dostępność każdej czcionki po nazwie i ręcznie określać warianty zastępcze. Deskryptor automatyzuje ten proces: zawiera macierz kompatybilności krojów — normalny, pogrubiony, kursywa, pogrubiona kursywa — a w przypadku braku dokładnego dopasowania zwraca najbliższy dostępny. Systemowe dopasowanie działa na poziomie Core Text i jest dostępne zarówno na iOS, jak i na macOS przez jednolity interfejs NSFontDescriptor API.
Deskryptory są również używane dla czcionek niestandardowych — załadowanych przez Info.plist lub dodanych ręcznie. Jeśli czcionka jest zarejestrowana w systemie, jej deskryptor tworzy się dokładnie tak samo jak dla systemowej. Uwaga międzyplatformowa: koncepcja deskryptora istnieje również w Androidzie przez Typeface.Builder, ale implementacja iOS przez UIFontDescriptor daje znacznie więcej atrybutów — ponad 20 wobec 5 w Androidzie.
UIFontDescriptor zawiera atrybuty zgrupowane w słowniku fontAttributes typu [UIFontDescriptor.AttributeName: Any]. Kluczowe atrybuty obejmują rodzinę czcionki (family), nazwę (name), rozmiar (size), krój (traits), macierz transformacji (matrix), rozmiar optyczny (opticalSize) i styl tekstu (textStyle). Według Apple WWDC 2019 Session 227, używanie stylów tekstu — Dynamic Type — jest obowiązkowe dla aplikacji zgodnych z accessibility.
Atrybut traits — to słownik zawierający charakterystyki symboli: grubość (UIFontWeightTrait), kursywę (UIFontSlantTrait), szerokość (UIFontWidthTrait) i inne. Te wartości są używane przez mechanizm dopasowania czcionek do wyboru kroju. Na przykład UIFontWeightTrait z wartością 0.0 — normalny krój, 0.3 — pogrubiony. System automatycznie mapuje wartości liczbowe na dostępne warianty czcionki.
Dodatkowe atrybuty obejmują featureSettings dla funkcji OpenType (ligatury, kerning, proporcje cyfr), visibleName do wyświetlania użytkownikowi, matrix dla afinicznych transformacji czcionki oraz cascadeList dla kaskadowych list czcionek zastępczych. Pełna lista atrybutów pokrywa praktycznie wszystkie scenariusze typografii w iOS i macOS.
| Atrybut | Typ | Opis |
|---|---|---|
| UIFontDescriptorFamily | String | Rodzina czcionki (SF Pro, Helvetica Neue) |
| UIFontDescriptorName | String | Pełna nazwa czcionki (HelveticaNeue-Bold) |
| UIFontDescriptorSize | NSNumber | Rozmiar czcionki w punktach |
| UIFontDescriptorMatrix | NSValue | Macierz afiniczna transformacji |
| UIFontDescriptorTraits | [String: Any] | Charakterystyki symboliczne kroju |
| UIFontDescriptorTextStyle | String | Styl Dynamic Type (headline, body, caption) |
Podstawowy sposób pracy z Font Descriptor w iOS — utworzenie deskryptora z następną generacją UIFont. To preferowane podejście, gdy trzeba uzyskać czcionkę z określonymi cechami bez znajomości dokładnej nazwy. Proces składa się z dwóch kroków: utworzenie UIFontDescriptor przez inicjalizator i wywołanie metody font(withSize:) na deskryptorze.
import UIKit
// Utwórz deskryptor czcionki dla rodziny
let descriptor = UIFontDescriptor.init(
fontAttributes: [
.family: "SF Pro",
.traits: [
.weight: UIFont.Weight.bold
]
]
)
// Generuj UIFont z deskryptora
let font = descriptor.font(withSize: 17)
To podejście gwarantuje, że system dobierze najlepsze dopasowanie dla pogrubionego kroju SF Pro na bieżącym urządzeniu. Kluczowa zaleta — kod nie zależy od wersji iOS: na iOS 13 zostanie użyty SF Pro, na wcześniejszych — Helvetica Neue lub domyślna czcionka systemowa.
Do tworzenia czcionki z dynamicznym rozmiarem używa się inicjalizatora ze stylem tekstu i skalą. Dynamic Type automatycznie dostosowuje rozmiar do ustawień użytkownika:
// Deskryptor Dynamic Type
let bodyDescriptor = UIFontDescriptor
.preferredFontDescriptor(withTextStyle: .body)
// Pogrub czcionkę
let boldDescriptor = bodyDescriptor.withSymbolicTraits([.traitBold])
// Generuj UIFont zachowując dynamiczny rozmiar
let boldBodyFont = UIFont(
descriptor: boldDescriptor!,
size: bodyDescriptor.pointSize
)
Ważne: metoda withSymbolicTraits zwraca opcjonalny deskryptor — jeśli żądany krój jest niedostępny, zwracana jest wartość nil. Zawsze sprawdzaj opcjonal przed użyciem.
Font Descriptor obsługuje model niemutowalny — każda metoda modyfikacji zwraca nowy deskryptor ze zmienionym atrybutem. Odpowiada to semantyce wartości i czyni kod przewidywalnym: oryginalny deskryptor nigdy się nie zmienia. Główne metody modyfikacji: addingAttributes do dodawania atrybutów, withFace do zmiany kroju, withSize do zmiany rozmiaru, withMatrix do afinicznej transformacji.
Metoda addingAttributes — najbardziej elastyczna. Przyjmuje słownik atrybutów i zwraca nowy deskryptor. W przypadku zgodności kluczy nowe wartości zastępują stare. Pozwala to łączyć zmiany: dodać wagę, zmienić rozmiar i włączyć ligatury jednym wywołaniem. Według Apple Technical Q&A QA1682, addingAttributes to zalecany sposób masowej modyfikacji przez rozszerzenie.
Praktyczne zastosowanie: tworzenie czcionki dla tekstu o stałej szerokości w edytorze kodu. Programista bierze systemowy deskryptor monospace, dodaje zmniejszoną wagę dla cienkich linii i zwiększa odstępy między znakami przez featureSettings. Daje to bardziej czytelny kod bez ładowania osobnej czcionki.
let monoDescriptor = UIFontDescriptor.monospacedDigitFontDescriptor()
// Dodaj niestandardowe atrybuty
let customDescriptor = monoDescriptor.addingAttributes([
.size: 14,
.traits: [
.weight: UIFont.Weight.medium
]
])
let monoFont = UIFont(
descriptor: customDescriptor,
size: 14
)
Ograniczenie: nie wszystkie atrybuty można zmienić po utworzeniu deskryptora. Na przykład rodzina czcionki (family) jest ustawiana raz podczas inicjalizacji. Jeśli trzeba zmienić rodzinę, utwórz nowy deskryptor. Wynika to z architektury Core Text, gdzie deskryptor jest związany z konkretnym zasobem czcionki.
Dopasowanie czcionek — kluczowa funkcja Font Descriptor, która automatycznie dobiera najlepsze dopasowanie do żądanych atrybutów spośród zainstalowanych czcionek. Proces obejmuje trzy etapy: filtracja (odrzucenie niezgodnych czcionek), rankingowanie (sortowanie według stopnia dopasowania) i wybór (zwrócenie najlepszego wyniku). Dopasowanie jest wykonywane na poziomie Core Text — frameworku leżącego u podstaw całej typografii iOS.
Do wyszukania wszystkich czcionek odpowiadających deskryptorowi używa się metody matchingFontDescriptors. Zwraca ona tablicę deskryptorów posortowanych według trafności. Programista może wybrać dokładne dopasowanie (pierwszy element) lub przeglądać warianty dla niestandardowej logiki. Według Apple Font Handling Guide, to jedyny sposób na uzyskanie listy dostępnych krojów dla konkretnej rodziny bez wyliczania po nazwie.
Scenariusz użycia: przy wyborze czcionki w interfejsie ustawień tekstu. Użytkownik wybiera rodzinę, a aplikacja przez matchingFontDescriptors pobiera wszystkie dostępne kroje i wyświetla je w pickerze. Bez dopasowania trzeba by sztywno kodować listę wariantów, która zmienia się między wersjami iOS.
let searchDescriptor = UIFontDescriptor.init(
fontAttributes: [.family: "SF Mono"]
)
// Pobierz wszystkie dostępne kroje
let matchingDescriptors = searchDescriptor
.matchingFontDescriptors(withMandatoryKeys: nil)
for descriptor in matchingDescriptors {
print(descriptor.object(forKey: .visibleName) ?? "unnamed")
}
Mandatory keys — parametr ograniczający wyszukiwanie. Jeśli podać [.family], dopasowanie zwróci wszystkie czcionki określonej rodziny. Jeśli podać [.family, .traits] — tylko te, które pasują zarówno do rodziny, jak i kroju. Użycie mandatory keys przyspiesza dopasowanie podczas wyszukiwania podzbioru czcionek.
Wydajność: dopasowanie to operacja synchroniczna zajmująca od 0.5 do 5 ms na iOS. Dla pojedynczego wyszukiwania jest to niezauważalne, ale przy masowym przeglądaniu deskryptorów (np. w pickerze z 50+ czcionkami) zaleca się buforowanie wyników. Apple zaleca wykonywanie dopasowania raz przy ładowaniu ekranu i zapisywanie tablicy deskryptorów.
Core Text — niskopoziomowy framework w języku C do pracy z typografią na iOS i macOS. Jego odpowiednik UIFontDescriptor — CTFontDescriptor, który zapewnia te same możliwości na poziomie Core Foundation. CTFontDescriptor jest używany w API Core Text do tworzenia czcionek, mierzenia tekstu i renderowania złożonej typografii. UIFontDescriptor w istocie jest nakładką Objective-C na CTFontDescriptor z rozszerzonym zestawem atrybutów.
Toll-free bridging między UIFontDescriptor a CTFontDescriptor pozwala przekazywać deskryptory między UIKit a Core Text bez konwersji. Jest to kluczowe dla aplikacji używających niestandardowego renderowania tekstu — na przykład edytorów tekstu opartych na TextKit lub edytorów kodu z podświetlaniem składni. Przykład: CTFontDescriptorCreateCopyWithAttribute tworzy kopię deskryptora z dodanym atrybutem — odpowiednik addingAttributes z UIFontDescriptor.
Key attribute kCTFontURLAttribute w CTFontDescriptor zawiera URL pliku czcionki. Pozwala to określić, czy czcionka jest systemowa, czy niestandardowa. Dla czcionek niestandardowych URL prowadzi do pliku czcionki (.ttf lub .otf), dla systemowych — do systemowego katalogu czcionek. Dane przez deskryptor są dostępne tylko do odczytu; zmiana pliku czcionki przez URL nie jest obsługiwana.
Do zaawansowanej typografii — niestandardowe ligatury, zamiany kontekstowe, alternatywne glify — używa się CTFontDescriptorCopyAttribute z kluczem kCTFontFeatureSettingsAttribute. Ten atrybut zawiera tablicę słowników funkcji OpenType, które można dodawać przez deskryptor. Według Apple Core Text Programming Guide, łączenie UIFontDescriptor z Core Text daje pełną kontrolę nad typografią aplikacji.
Często zadawane pytania
UIFont — to gotowa do użycia czcionka, która renderuje tekst. Font Descriptor — to opis czcionki, zestaw atrybutów, z których można utworzyć UIFont. Jeden deskryptor może wygenerować wiele UIFont o różnych rozmiarach.
Tak. Jeśli czcionka jest zarejestrowana w systemie (przez Info.plist lub Core Graphics), jej deskryptor tworzy się po rodzinie lub nazwie dokładnie tak samo jak dla czcionek systemowych. Dopasowanie działa dla wszystkich zarejestrowanych czcionek.
Użyj descriptor.object(forKey: .visibleName), aby uzyskać wyświetlaną nazwę, lub descriptor.postscriptName dla nazwy PostScript. Nazwa PostScript jest używana podczas tworzenia czcionki przez UIFont(name:size:).
Cascade list — to tablica zagnieżdżonych deskryptorów, które służą jako czcionki zastępcze. Jeśli główna czcionka nie zawiera potrzebnego znaku, system kolejno sprawdza czcionki z cascade list. Używane do obsługi emoji i znaków CJK.
Tak. SwiftUI obsługuje Font Descriptor przez Font(descriptor:size:). Nakładka SwiftUI przyjmuje UIFontDescriptor i tworzy czcionkę SwiftUI, zachowując wszystkie atrybuty deskryptora — kerning, ligatury i krój.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również