Dynamic Type — wbudowana funkcja iOS, która automatycznie zmienia rozmiar czcionki w aplikacji zgodnie z systemowymi ustawieniami użytkownika. Użytkownik ustawia preferowany rozmiar tekstu w Ustawieniach → Ekran i jasność → Rozmiar tekstu, a wszystkie aplikacje obsługujące Dynamic Type dostosowują się bez dodatkowych działań. Według Apple Human Interface Guidelines, 2024, obsługa Dynamic Type jest obowiązkowym wymogiem publikacji w App Store, ponieważ jest to podstawowy element dostępności na platformie iOS.
Najważniejsze
Dynamic Type — technologia iOS, wprowadzona w iOS 7, która pozwala tekstowi w aplikacji automatycznie dostosowywać się do systemowych ustawień rozmiaru czcionki. Użytkownik może zwiększyć lub zmniejszyć czcionkę we wszystkich aplikacjach jednocześnie — bez konieczności zmiany ustawień w każdej aplikacji osobno.
Według Apple WWDC 2023, „Make Your App Visually Accessible”, ponad 40% użytkowników iOS zmienia rozmiar czcionki względem standardowego. Dla grupy wiekowej 65+ wskaźnik ten osiąga 70%. Dynamic Type jest obowiązkowym wymogiem certyfikacji dostępności App Store. Brak obsługi jest powodem odrzucenia aplikacji podczas przeglądu.
Zasada działania: aplikacja używa UIFont.preferredFont(forTextStyle:) zamiast UIFont(name:size:). iOS automatycznie zwraca czcionkę przeskalowaną do bieżącego ustawienia systemowego. Przy zmianie rozmiaru w ustawieniach iOS generuje powiadomienie UIContentSizeCategory.didChangeNotification — aplikacja musi przeliczyć układ.
Dynamic Type pojawił się w iOS 7 wraz z „płaskim” designem. W iOS 10 dodano obsługę niestandardowych czcionek przez UIFontMetrics. iOS 11 wprowadził poziomy dostępności (do AccessibilityXXXL). iOS 15 dodał Dynamic Type w SwiftUI z automatyczną obsługą. Z każdą wersją Apple zaostrza wymagania: od iOS 17 aplikacje bez obsługi Dynamic Type otrzymują ostrzeżenie podczas przesyłania do App Store Connect.
iOS udostępnia 8 stylów tekstowych, każdy z predefiniowanym rozmiarem i krojem dla standardowego ustawienia:
| Styl | Stała | Rozmiar (L) | Przeznaczenie |
|---|---|---|---|
| Large Title | .largeTitle | 34px | Główny tytuł ekranu |
| Title 1 | .title1 | 28px | Tytuł sekcji |
| Title 2 | .title2 | 22px | Podtytuł |
| Title 3 | .title3 | 20px | Tytuł karty |
| Headline | .headline | 17px (bold) | Pogrubienie dla akcentów |
| Body | .body | 17px | Tekst główny |
| Callout | .callout | 16px | Tekst pomocniczy |
| Caption 1 | .caption1 | 12px | Podpis pod obrazem |
| Caption 2 | .caption2 | 11px | Drobny podpis |
| Footnote | .footnote | 13px | Przypis, uwaga |
Używanie odpowiedniego stylu to nie tylko „wygląd”. UIFont.TextStyle.body w trybie AccessibilityXXXL może osiągnąć 53px. Jeśli aplikacja używa stałej czcionki 17px dla body, tekst stanie się nieczytelny dla użytkowników, którzy powiększyli czcionkę.
Dynamic Type nie tylko skaluje — zachowuje hierarchię wizualną. Large Title jest zawsze większy od Title 1, który jest większy od Body, niezależnie od poziomu skalowania. Współczynniki skalowania różnią się: nagłówki skalują się aktywniej niż tekst główny, aby hierarchia była zachowana nawet na poziomach dostępności.
iOS obsługuje 11 poziomów skalowania tekstu, podzielonych na dwie kategorie:
Różnica między XS a AccessibilityXXXL dla stylu body wynosi od 14px do 53px — prawie 4×. Układ zaprojektowany na 17px całkowicie się psuje przy 53px: tekst wychodzi poza granice, przyciski nachodzą na siebie, komórki nakładają się.
Sprawdź bieżącą kategorię w kodzie:
let category = UIApplication.shared.preferredContentSizeCategory
// .extraSmall, .small, .medium, .large, .extraLarge ...
if category.isAccessibilityCategory {
// Włącz alternatywny układ
}
Kategoria rozmiaru tekstu jest dostępna przez traitCollection.uiContentSizeCategory. Przy zmianie ustawienia systemowego iOS wywołuje traitCollectionDidChange na wszystkich UIView. W tej metodzie należy zaktualizować czcionki i przeliczyć układ. SwiftUI robi to automatycznie — UIKit wymaga ręcznej subskrypcji.
Dla UICollectionView używaj UICollectionViewCompositionalLayout — automatycznie dostosowuje liczbę kolumn do szerokości ekranu i rozmiaru tekstu. Na poziomach dostępności przełączaj się z dwukolumnowego na jednokolumnowy układ, aby tekst nie był obcinany, a elementy nie nachodziły na siebie. Używaj warunkowego układu: dla regular width — dwie kolumny, dla compact lub accessibility — jedna kolumna.
Podstawowa implementacja w UIKit — UIFont.preferredFont(forTextStyle:). Ta metoda zwraca czcionkę przeskalowaną do bieżącego ustawienia systemowego:
titleLabel.font = UIFont.preferredFont(forTextStyle: .headline)
bodyLabel.font = UIFont.preferredFont(forTextStyle: .body)
Dla niestandardowych czcionek używaj UIFontMetrics:
let customFont = UIFont(name: "Montserrat-Regular", size: 16)!
titleLabel.font = UIFontMetrics(forTextStyle: .body)
.scaledFont(for: customFont)
// Śledzenie zmian rozmiaru
NotificationCenter.default.addObserver(
self,
selector: #selector(preferredContentSizeChanged),
name: UIContentSizeCategory.didChangeNotification,
object: nil
)
Dla UILabel w Interface Builder wystarczy ustawić czcionkę jako styl tekstowy (Text Style) i włączyć „Automatically Adjusts Font”. Dla niestandardowych czcionek IB nie obsługuje UIFontMetrics — tylko przez kod.
UIFontMetrics używa tej samej krzywej skalowania co preferredFont. Możesz ustawić fromTextStyle: .body, .headline itd. Każdy styl ma swój współczynnik skalowania. Body skaluje się umiarkowanie, Large Title — agresywnie. Jeśli twoja niestandardowa czcionka jest używana do tekstu głównego, używaj .body.
W SwiftUI obsługa Dynamic Type jest wbudowana domyślnie. Wszystkie systemowe modyfikatory (.font(.body), .font(.title)) automatycznie skalują się. Programista nie musi wywoływać UIFont.preferredFont.
Przykład:
Text("Tekst główny")
.font(.body)
.lineLimit(nil)
.minimumScaleFactor(0.5)
Dla niestandardowych skal używaj DynamicTypeSize:
@Environment(\.dynamicTypeSize) var dynamicTypeSize
var body: some View {
Text("Tekst adaptacyjny")
.font(.body)
.padding(dynamicTypeSize <= .large ? 8 : 16)
}
SwiftUI automatycznie aktualizuje widok przy zmianie systemowego rozmiaru tekstu — żadnych dodatkowych subskrypcji powiadomień.
Modyfikator .font(.body) działa tylko dla systemowej czcionki. Dla niestandardowych czcionek w SwiftUI używaj Font.custom z UIFontMetrics pod spodem. Od iOS 16 SwiftUI obsługuje DynamicTypeSize w @Environment, co pozwala dostosować odstępy i układ.
Auto Layout — obowiązkowy warunek obsługi Dynamic Type. Stałe szerokości i wysokości (>=, <=) psują się przy rozmiarach dostępności. Używaj intrinsicContentSize dla UILabel — automatycznie oblicza wysokość pod bieżący rozmiar czcionki.
Zasady adaptacyjnego układu:
Dla długich tekstów (np. artykuły, warunki użytkowania) ustaw minimumScaleFactor na UILabel — zmniejsza to tekst w ostateczności, gdy Auto Layout nie może pomieścić treści. Wartość 0.5 oznacza, że czcionka może zmniejszyć się do 50% preferowanego rozmiaru.
Przykład dostosowania odstępów do kategorii rozmiaru:
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)
Obcinanie tekstu — UILabel z numberOfLines = 1 i stałą szerokością obcina tekst na AccessibilityXL. Rozwiązanie: numberOfLines = 0 i trailing constraint. Nachodzenie elementów — przyciski o stałej wysokości nachodzą na siebie. Rozwiązanie: UIStackView z automatic spacing. Wychodzenie poza ekran — ScrollView jest obowiązkowy na poziomach dostępności.
Symulator Xcode pozwala zmienić rozmiar tekstu: w menu symulatora Settings → Accessibility → Display & Text Size → Larger Text. Przełączaj między wszystkimi 11 poziomami i sprawdzaj, czy tekst nie jest obcinany, przyciski są dostępne, a układ nie jest zepsuty.
Do testów automatycznych używaj ustawienia contentSizeCategory w XCUIApplication:
func testAccessibilitySizes() {
let app = XCUIApplication()
app.launchArguments += [
"-UIPreferredContentSizeCategoryName",
"UICTContentSizeCategoryAccessibilityXXXL"
]
app.launch()
app.scrollViews.buttons["Wyślij"].tap()
XCTAssertTrue(app.staticTexts["Formularz wysłany"]
.waitForExistence(timeout: 5))
}
XCUITest z różnymi launchArguments pozwala sprawdzić wszystkie poziomy skalowania w CI. Nie zapomnij sprawdzić kategorii dostępności osobno — one najczęściej psują układ. Według Apple, 70% błędów Dynamic Type wykrywanych jest właśnie na poziomach dostępności, ponieważ programiści testują tylko standardowe rozmiary.
Xcode Accessibility Inspector pokazuje, jakich czcionek używa wybrany element — stałej czy skalowalnej. Jeśli element nie reaguje na zmianę rozmiaru tekstu w symulatorze, oznacza to, że używana jest stała czcionka. Zastąp ją UIFont.preferredFont lub UIFontMetrics.
Często zadawane pytania
To automatyczne skalowanie tekstu w aplikacji zgodnie z systemowymi ustawieniami rozmiaru. Użytkownik zmienia rozmiar w Ustawieniach — wszystkie obsługujące to aplikacje dostosowują się bez udziału programisty.
Nie. Dla niestandardowych czcionek używaj UIFontMetrics(scaledFont:). Metoda skaluje dowolną czcionkę względem określonego stylu tekstowego, zachowując proporcje.
11 poziomów: 5 standardowych (XS, S, M, L, XL) i 6 poziomów dostępności (od AccessibilityXL do AccessibilityXXXXXL). Rozmiar czcionki body może wahać się od 14px do 53px.
W UIKit przez UIContentSizeCategory.didChangeNotification. W SwiftUI używaj @Environment(\.dynamicTypeSize) — widok zaktualizuje się automatycznie przy zmianie ustawienia systemowego.
Użytkownicy z powiększoną czcionką zobaczą obcięty tekst, nachodzące na siebie elementy i niedziałające przyciski. Aplikacja może zostać odrzucona podczas przeglądu App Store za naruszenie wymogów dostępności.
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ż