Dynamic Type — o funcție încorporată în iOS care modifică automat dimensiunea fontului în aplicație în funcție de setările sistemului utilizatorului. Utilizatorul stabilește dimensiunea preferată a textului în Setări → Ecran și luminozitate → Dimensiune text, iar toate aplicațiile care acceptă Dynamic Type se adaptează fără acțiuni suplimentare. Conform Apple Human Interface Guidelines, 2024, suportul pentru Dynamic Type este o cerință obligatorie pentru publicarea în App Store, deoarece este un element de bază al accesibilității pe platforma iOS.
Elemente esențiale
Dynamic Type — tehnologia iOS, apărută în iOS 7, care permite textului din aplicație să se adapteze automat la setările sistemului pentru dimensiunea fontului. Utilizatorul poate mări sau micșora fontul în toate aplicațiile simultan — fără a fi nevoie să schimbe setările în fiecare aplicație în parte.
Conform Apple WWDC 2023, „Make Your App Visually Accessible”, peste 40% dintre utilizatorii iOS modifică dimensiunea fontului față de cea standard. Pentru grupa de vârstă 65+, acest indicator atinge 70%. Dynamic Type este o cerință obligatorie pentru certificarea de accesibilitate App Store. Absența suportului este un motiv de respingere a aplicației la revizuire.
Principiu de funcționare: aplicația folosește UIFont.preferredFont(forTextStyle:) în loc de UIFont(name:size:). iOS returnează automat fontul scalat în funcție de setarea curentă a sistemului. La modificarea dimensiunii în setări, iOS generează notificarea UIContentSizeCategory.didChangeNotification — aplicația trebuie să recalculeze aspectul.
Dynamic Type a apărut în iOS 7 odată cu designul „plat”. În iOS 10 a fost adăugat suportul pentru fonturi personalizate prin UIFontMetrics. iOS 11 a introdus nivelurile de accesibilitate (până la AccessibilityXXXL). iOS 15 a adăugat Dynamic Type în SwiftUI cu suport automat. Cu fiecare versiune, Apple înăsprește cerințele: începând cu iOS 17, aplicațiile fără suport Dynamic Type primesc un avertisment la încărcarea în App Store Connect.
iOS oferă 8 stiluri de text, fiecare cu o dimensiune și un caracter prestabilit pentru setarea standard:
| Stil | Constantă | Dimensiune (L) | Scop |
|---|---|---|---|
| Large Title | .largeTitle | 34px | Titlul principal al ecranului |
| Title 1 | .title1 | 28px | Titlul secțiunii |
| Title 2 | .title2 | 22px | Subtitlu |
| Title 3 | .title3 | 20px | Titlul cardului |
| Headline | .headline | 17px (bold) | Bold pentru accent |
| Body | .body | 17px | Text principal |
| Callout | .callout | 16px | Text auxiliar |
| Caption 1 | .caption1 | 12px | Legendă sub imagine |
| Caption 2 | .caption2 | 11px | Legendă mică |
| Footnote | .footnote | 13px | Notă de subsol |
Folosirea stilului corect nu este doar „aspect vizual”. UIFont.TextStyle.body în modul AccessibilityXXXL poate atinge 53px. Dacă aplicația folosește un font fix de 17px pentru body, textul va deveni ilizibil pentru utilizatorii care au mărit fontul.
Dynamic Type nu doar scalează — păstrează ierarhia vizuală. Large Title este întotdeauna mai mare decât Title 1, care este mai mare decât Body, indiferent de nivelul de scalare. Coeficienții de scalare diferă: titlurile se scalează mai activ decât textul principal, pentru ca ierarhia să se păstreze chiar și la nivelurile de accesibilitate.
iOS acceptă 11 niveluri de scalare a textului, împărțite în două categorii:
Diferența între XS și AccessibilityXXXL pentru stilul body este de la 14px la 53px — aproape 4×. Aspectul proiectat pentru 17px se strică complet la 53px: textul iese din limite, butoanele se suprapun, celulele se acoperă reciproc.
Verificați categoria curentă în cod:
let category = UIApplication.shared.preferredContentSizeCategory
// .extraSmall, .small, .medium, .large, .extraLarge ...
if category.isAccessibilityCategory {
// Activare aspect alternativ
}
Categoria dimensiunii textului este disponibilă prin traitCollection.uiContentSizeCategory. La modificarea setării sistemului, iOS apelează traitCollectionDidChange pe toate UIView-urile. În această metodă trebuie actualizate fonturile și recalculat aspectul. SwiftUI face acest lucru automat — UIKit necesită abonare manuală.
Pentru UICollectionView, folosiți UICollectionViewCompositionalLayout — acesta ajustează automat numărul de coloane în funcție de lățimea ecranului și dimensiunea textului. La nivelurile de accesibilitate, treceți de la aspectul cu două coloane la unul cu o singură coloană, pentru ca textul să nu fie tăiat și elementele să nu se suprapună. Folosiți un aspect condițional: pentru regular width — două coloane, pentru compact sau accessibility — o coloană.
Implementarea de bază în UIKit — UIFont.preferredFont(forTextStyle:). Această metodă returnează fontul scalat în funcție de setarea curentă a sistemului:
titleLabel.font = UIFont.preferredFont(forTextStyle: .headline)
bodyLabel.font = UIFont.preferredFont(forTextStyle: .body)
Pentru fonturi personalizate folosiți UIFontMetrics:
let customFont = UIFont(name: "Montserrat-Regular", size: 16)!
titleLabel.font = UIFontMetrics(forTextStyle: .body)
.scaledFont(for: customFont)
// Urmărirea modificărilor de dimensiune
NotificationCenter.default.addObserver(
self,
selector: #selector(preferredContentSizeChanged),
name: UIContentSizeCategory.didChangeNotification,
object: nil
)
Pentru UILabel în Interface Builder, este suficient să setați fontul ca stil de text (Text Style) și să activați „Automatically Adjusts Font”. Pentru fonturile personalizate, IB nu acceptă UIFontMetrics — doar prin cod.
UIFontMetrics folosește aceeași curbă de scalare ca și preferredFont. Puteți seta fromTextStyle: .body, .headline etc. Fiecare stil are propriul coeficient de scalare. Body se scalează moderat, Large Title — agresiv. Dacă fontul dumneavoastră personalizat este folosit pentru textul principal, utilizați .body.
În SwiftUI, suportul pentru Dynamic Type este încorporat implicit. Toți modificatorii de sistem (.font(.body), .font(.title)) se scalează automat. Dezvoltatorul nu trebuie să apeleze UIFont.preferredFont.
Exemplu:
Text("Text principal")
.font(.body)
.lineLimit(nil)
.minimumScaleFactor(0.5)
Pentru scale personalizate utilizați DynamicTypeSize:
@Environment(\.dynamicTypeSize) var dynamicTypeSize
var body: some View {
Text("Text adaptiv")
.font(.body)
.padding(dynamicTypeSize <= .large ? 8 : 16)
}
SwiftUI actualizează automat vizualizarea la modificarea dimensiunii sistemului de text — fără abonamente suplimentare la notificări.
Modificatorul .font(.body) funcționează doar pentru fontul de sistem. Pentru fonturi personalizate în SwiftUI, utilizați Font.custom cu UIFontMetrics sub capotă. începând cu iOS 16, SwiftUI acceptă DynamicTypeSize în @Environment, ceea ce permite adaptarea spațierilor și a aspectului.
Auto Layout — condiția obligatorie pentru suportul Dynamic Type. Lățimile și înălțimile fixe (>=, <=) se strică la dimensiunile de accesibilitate. Folosiți intrinsicContentSize pentru UILabel — acesta calculează automat înălțimea în funcție de dimensiunea curentă a fontului.
Reguli pentru aspect adaptiv:
Pentru texte lungi (de exemplu, articole, termeni de utilizare), setați minimumScaleFactor pe UILabel — aceasta micșorează textul ca ultimă soluție atunci când Auto Layout nu poate încăpea conținutul. Valoarea 0.5 înseamnă că fontul se poate micșora până la 50% din dimensiunea preferată.
Exemplu de adaptare a spațierilor la categoria de dimensiune:
let isAccessibility = traitCollection
.preferredContentSizeCategory.isAccessibilityCategory
stackView.spacing = isAccessibility ? 16 : 8
button.contentEdgeInsets = isAccessibility
? UIEdgeInsets(top: 16, left: 24, bottom: 16, right: 24)
: UIEdgeInsets(top: 8, left: 16, bottom: 8, right: 16)
Tăierea textului — UILabel cu numberOfLines = 1 și lățime fixă taie textul la AccessibilityXL. Soluție: numberOfLines = 0 și trailing constraint. Suprapunerea elementelor — butoanele cu înălțime fixă se suprapun. Soluție: UIStackView cu spațiere automată. Ieșirea în afara ecranului — ScrollView este obligatoriu la nivelurile de accesibilitate.
Simulatorul Xcode permite schimbarea dimensiunii textului: în meniul simulatorului Settings → Accessibility → Display & Text Size → Larger Text. Comutați între toate cele 11 niveluri și verificați dacă textul nu este tăiat, butoanele sunt accesibile și aspectul nu este stricat.
Pentru testare automatizată utilizați setarea contentSizeCategory în XCUIApplication:
func testAccessibilitySizes() {
let app = XCUIApplication()
app.launchArguments += [
"-UIPreferredContentSizeCategoryName",
"UICTContentSizeCategoryAccessibilityXXXL"
]
app.launch()
app.scrollViews.buttons["Trimite"].tap()
XCTAssertTrue(app.staticTexts["Formular trimis"]
.waitForExistence(timeout: 5))
}
XCUITest cu diferite launchArguments permite verificarea tuturor nivelurilor de scalare în CI. Nu uitați să verificați separat categoriile de accesibilitate — ele strică cel mai des aspectul. Conform Apple, 70% dintre erorile Dynamic Type sunt detectate tocmai la nivelurile de accesibilitate, deoarece dezvoltatorii testează doar dimensiunile standard.
Xcode Accessibility Inspector arată ce fonturi folosește elementul selectat — fix sau scalabil. Dacă elementul nu reacționează la modificarea dimensiunii textului în simulator, înseamnă că se folosește un font fix. Înlocuiți-l cu UIFont.preferredFont sau UIFontMetrics.
Întrebări frecvente
Este scalarea automată a textului în aplicație în funcție de setările sistemului pentru dimensiune. Utilizatorul schimbă dimensiunea în Setări — toate aplicațiile care acceptă această funcție se adaptează fără implicarea dezvoltatorului.
Nu. Pentru fonturi personalizate folosiți UIFontMetrics(scaledFont:). Metoda scalează orice font în raport cu stilul de text specificat, păstrând proporțiile.
11 niveluri: 5 standard (XS, S, M, L, XL) și 6 niveluri de accesibilitate (de la AccessibilityXL la AccessibilityXXXXXL). Dimensiunea fontului body poate varia de la 14px la 53px.
În UIKit prin UIContentSizeCategory.didChangeNotification. În SwiftUI folosiți @Environment(\.dynamicTypeSize) — vizualizarea se va actualiza automat la modificarea setării sistemului.
Utilizatorii cu font mărit vor vedea text tăiat, elemente suprapuse și butoane nefuncționale. Aplicația poate fi respinsă la revizuirea App Store pentru încălcarea cerințelor de accesibilitate.
Concluzii
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și