Dynamic Type: kluczowe pojęcia, style tekstowe i jak działa w iOS

Autor: IT Sectr Opublikowano: 2026-05-16 Czas czytania: 9 min

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 — mechanizm iOS do automatycznego skalowania tekstu zgodnie z systemowymi ustawieniami rozmiaru czcionki
  • Obsługa zapewniana jest przez style tekstowe (UIFont.TextStyle) — body, headline, caption, title i inne
  • System obsługuje 11 poziomów skalowania od XSmall do AccessibilityXXXL
  • Dla niestandardowych czcionek używana jest metoda UIFontMetrics, skalująca dowolną czcionkę względem stylu body
  • Układ musi być adaptacyjny — UIStackView, Auto Layout i dynamiczna wysokość komórek są obowiązkowe

Czym jest Dynamic Type w iOS

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.

Historia rozwoju Dynamic Type

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.

Style tekstowe UIFont.TextStyle

iOS udostępnia 8 stylów tekstowych, każdy z predefiniowanym rozmiarem i krojem dla standardowego ustawienia:

StylStałaRozmiar (L)Przeznaczenie
Large Title.largeTitle34pxGłówny tytuł ekranu
Title 1.title128pxTytuł sekcji
Title 2.title222pxPodtytuł
Title 3.title320pxTytuł karty
Headline.headline17px (bold)Pogrubienie dla akcentów
Body.body17pxTekst główny
Callout.callout16pxTekst pomocniczy
Caption 1.caption112pxPodpis pod obrazem
Caption 2.caption211pxDrobny podpis
Footnote.footnote13pxPrzypis, 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ę.

Hierarchia wizualna przez style

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.

Poziomy skalowania

iOS obsługuje 11 poziomów skalowania tekstu, podzielonych na dwie kategorie:

  • Standardowe rozmiary (5 poziomów): XS, S, M, L (domyślnie), XL
  • Rozmiary dostępności (6 poziomów): accessibilityXL, accessibilityXXL, accessibilityXXXL, accessibilityXXXXL, accessibilityXXXXXL, accessibilityXXXXXXL

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:

swift
let category = UIApplication.shared.preferredContentSizeCategory
// .extraSmall, .small, .medium, .large, .extraLarge ...
if category.isAccessibilityCategory {
    // Włącz alternatywny układ
}

traitCollection i rozmiar tekstu

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.

Implementacja w UIKit

Podstawowa implementacja w UIKit — UIFont.preferredFont(forTextStyle:). Ta metoda zwraca czcionkę przeskalowaną do bieżącego ustawienia systemowego:

swift
titleLabel.font = UIFont.preferredFont(forTextStyle: .headline)
bodyLabel.font = UIFont.preferredFont(forTextStyle: .body)

Dla niestandardowych czcionek używaj UIFontMetrics:

swift
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 i krzywa skalowania

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.

Dynamic Type w SwiftUI

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:

swift
Text("Tekst główny")
    .font(.body)
    .lineLimit(nil)
    .minimumScaleFactor(0.5)

Dla niestandardowych skal używaj DynamicTypeSize:

swift
@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ń.

Ograniczenie Dynamic Type w SwiftUI

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.

Adaptacja układu pod duże czcionki

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:

  • UIStackView z distribution = fill i spacing = >= 8 — elementy będą przenoszone do następnego wiersza
  • UITableViewCell z automaticDimension — wysokość komórki dostosowuje się do treści
  • numberOfLines = 0 na UILabel — tekst nie jest obcinany, ale zawijany
  • Przyciski z edgeInsets — dodaj odstępy na poziomach dostępności przez traitCollection.preferredContentSizeCategory

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:

swift
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)

Typowe problemy układu na poziomach dostępności

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.

Testowanie Dynamic Type

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:

swift
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.

Accessibility Inspector: sprawdzanie Dynamic Type

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

Czym jest Dynamic Type w iOS prostymi słowami?

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.

Czy Dynamic Type działa tylko z systemowymi czcionkami?

Nie. Dla niestandardowych czcionek używaj UIFontMetrics(scaledFont:). Metoda skaluje dowolną czcionkę względem określonego stylu tekstowego, zachowując proporcje.

Ile poziomów skalowania obsługuje iOS?

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.

Jak zasubskrybować zmiany rozmiaru tekstu?

W UIKit przez UIContentSizeCategory.didChangeNotification. W SwiftUI używaj @Environment(\.dynamicTypeSize) — widok zaktualizuje się automatycznie przy zmianie ustawienia systemowego.

Co się stanie, jeśli nie obsłużę Dynamic Type?

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

  • Dynamic Type — wbudowany mechanizm iOS do skalowania tekstu zgodnie z ustawieniami systemowymi; obowiązkowy dla App Store
  • Używaj UIFont.preferredFont(forTextStyle:) dla systemowych czcionek i UIFontMetrics dla niestandardowych
  • iOS obsługuje 11 poziomów skalowania — od XS do AccessibilityXXXXXL (14–53px dla body)
  • W SwiftUI Dynamic Type działa automatycznie przez .font(.body) i @Environment(\.dynamicTypeSize)
  • Układ musi być adaptacyjny: UIStackView, automaticDimension w tabelach, numberOfLines = 0
  • Testuj wszystkie 11 poziomów, szczególnie kategorie dostępności — na nich psuje się 70% układów
  • Subskrypcja UIContentSizeCategory.didChangeNotification jest obowiązkowa dla aplikacji UIKit

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.

Omów projekt

Przeczytaj również