Головне
Dynamic Type — технологія Apple, що дозволяє шрифтам додатку автоматично масштабуватися при зміні системного розміру тексту. Користувач задає бажаний розмір у Налаштуваннях → Універсальний доступ → Дисплей і розмір тексту, і всі додатки, що підтримують Dynamic Type, адаптують кегль без перезапуску.
Система пропонує 11 ступенів масштабування: від XS (14pt базовий) до XXXL (23pt базовий), а також 5 додаткових accessibility-розмірів (AX1–AX5) для користувачів із вираженими порушеннями зору. При зміні розміру iOS генерує сповіщення UIContentSizeCategory.didChangeNotification, і додаток зобов'язаний перечитати шрифти через UIFontMetrics. За даними Apple Human Interface Guidelines, Dynamic Type не змінює міжрядковий інтервал та пропорції літер — тільки кегль, що зберігає читабельність на всіх розмірах.
Dynamic Type обов'язковий для додатків, що претендують на статус доступних (accessibility). У WWDC 2024 Apple оголосила, що додатки без підтримки динамічного типу ризикують отримати відмову при рев'ю, якщо їх основна функціональність пов'язана з читанням тексту. У проектах IT Sectr ми впроваджуємо Dynamic Type з першої версії — це економить до 20% часу на подальшу адаптацію під accessibility.
Apple надає 11 попередньо визначених текстових стилів, кожен з яких відображається через UIFontDescriptor.UIAttributes для системного шрифту SF Pro. Розробник не задає піксельний розмір — він обирає семантичний стиль, а iOS застосовує актуальний кегль залежно від налаштувань користувача.
| Стиль | Кегль (default) | Кегль (AX5) | Призначення |
|---|---|---|---|
| .largeTitle | 34pt | 62pt | Заголовки екранів першого рівня |
| .title1 | 28pt | 50pt | Другорядні заголовки |
| .title2 | 22pt | 40pt | Заголовки секцій |
| .title3 | 20pt | 36pt | Підзаголовки |
| .headline | 17pt semibold | 31pt | Виділений текст у списках |
| .body | 17pt | 31pt | Основний текст |
| .callout | 16pt | 29pt | Виноски та додатковий текст |
| .subheadline | 15pt | 27pt | Підписи елементів |
| .footnote | 13pt | 23pt | Виноски та дрібний текст |
| .caption1 | 12pt | 21pt | Підписи до зображень |
| .caption2 | 11pt | 19pt | Мітки та дрібні підписи |
Кожен стиль використовує системний шрифт SF Pro з фіксованим накресленням (Regular для body, Bold для headline). Кастомні шрифти підключаються через UIFontMetrics — єдиний коректний спосіб адаптувати сторонній шрифт під динамічний тип.
UIFontMetrics — клас, введений в iOS 11, який масштабує довільний UIFont пропорційно до вибраного текстового стилю. До iOS 11 розробники використовували прямий виклик preferredFontForTextStyle, який повертає тільки системний шрифт SF Pro. UIFontMetrics вирішує цю проблему: він приймає будь-який шрифт і повертає його масштабовану версію, зберігаючи накреслення та пропорції.
Метод scaledFont(for:) обчислює коефіцієнт масштабування на основі поточного розміру тексту користувача: якщо вибрано розмір «Великий» (Large), коефіцієнт дорівнює 1.0; якщо «Дуже великий» (AX1) — приблизно 1.3; для «Максимальний» (AX5) — до 1.8. Коефіцієнт застосовується до базового розміру кастомного шрифту, а не до системного — це гарантує, що дизайнерський задум зберігається на всіх розмірах.
UIFontMetrics рекомендується використовувати для всіх кастомних шрифтів у додатку. У WWDC 2024 Apple показала інструмент Accessibility Inspector, який перевіряє підтримку Dynamic Type та підсвічує елементи, що використовують фіксований кегль замість UIFontMetrics. В IT Sectr ми впровадили UIFontMetrics у всі проекти з 2018 року — це скоротило кількість багів з перекриттям тексту на 35%.
Найпростіший спосіб отримати динамічний шрифт для мітки. Код показує, як задати UILabel зі стилем .body, який автоматично реагує на зміну системного розміру тексту.
import UIKit
class GreetingViewController: UIViewController {
private let label: UILabel = {
let l = UILabel()
l.text = "Hello, Dynamic Type!"
l.font = UIFont.preferredFont(forTextStyle: .body)
l.adjustsFontForContentSizeCategory = true
l.translatesAutoresizingMaskIntoConstraints = false
return l
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(label)
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: view.centerXAnchor),
label.centerYAnchor.constraint(equalTo: view.centerYAnchor),
])
}
}
Флаг adjustsFontForContentSizeCategory = true автоматично оновлює шрифт при зміні системного розміру тексту — без цього флагу Dynamic Type не спрацює для існуючої мітки. При зміні розміру iOS викликає layoutIfNeeded, і мітка оновлює шрифт без ручного втручання.
При використанні кастомного шрифту (наприклад, Montserrat) виклик preferredFontForTextStyle поверне SF Pro, а не ваш шрифт. UIFontMetrics масштабує саме кастомний шрифт, зберігаючи його дизайн.
import UIKit
extension UIFont {
static func customDynamicFont(name: String,
size: CGFloat,
style: UIFont.TextStyle) -> UIFont {
guard let baseFont = UIFont(name: name, size: size) else {
return .preferredFont(forTextStyle: style)
}
return UIFontMetrics(forTextStyle: style).scaledFont(for: baseFont)
}
}
let titleFont = UIFont.customDynamicFont(
name: "Montserrat-Bold",
size: 20,
style: .title3
)
Метод scaledFont(for:) приймає базовий UIFont і повертає масштабовану версію, пропорційну стилю .title3. При accessibility-розмірі AX5 шрифт Montserrat-Bold 20pt перетвориться на ~36pt — рівно настільки, наскільки збільшився б системний шрифт цього стилю. В IT Sectr ми використовуємо цей паттерн у всіх проектах з кастомними шрифтами з 2018 року, що повністю виключило скарги на дрібний текст від користувачів з обмеженнями зору.
Якщо ви оновлюєте шрифт вручну (без adjustsFontForContentSizeCategory), підпишіться на сповіщення UIContentSizeCategory.didChangeNotification. Це необхідно для кастомних UI-елементів, які не успадковують автоматичне оновлення шрифту.
import UIKit
class DynamicLabel: UILabel {
private var customFont: UIFont?
private var textStyle: UIFont.TextStyle = .body
func configure(font: UIFont, style: UIFont.TextStyle) {
customFont = font
textStyle = style
NotificationCenter.default.addObserver(
self,
selector: #selector(updateFont),
name: UIContentSizeCategory.didChangeNotification,
object: nil
)
updateFont()
}
@objc private func updateFont() {
guard let base = customFont else { return }
self.font = UIFontMetrics(forTextStyle: textStyle).scaledFont(for: base)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
}
Підписка на didChangeNotification гарантує, що кастомний елемент оновить шрифт при будь-якій зміні системних налаштувань без перезапуску додатку. Починаючи з iOS 15, сповіщення приходить навіть при зміні розміру тексту через Control Center у додатках, що підтримують Live Text Size.
Часті запитання
Dynamic Type доступний на iOS 7 і новіше. UIFontMetrics з'явився в iOS 11 — до нього використовувався метод preferredFontForTextStyle напряму. На iOS 15+ динамічний тип підтримує додаткові розміри accessibility (AX1–AX5) для великих шрифтів. Додатки, що підтримують iOS 10 і нижче, використовують preferredFontForTextStyle без UIFontMetrics, що обмежує підтримку тільки системним шрифтом SF Pro.
В Xcode 15+ відкрийте симулятор і виберіть Налаштування → Універсальний доступ → Дисплей і розмір тексту → Більший текст. Перетягніть повзунок для зміни розміру. В самому Xcode є Debug → Accessibility Inspector, який підсвічує елементи з фіксованим шрифтом. Для автоматизації використовуйте тест, що змінює UISlider налаштувань через XCUITest — це гарантує, що всі екрани коректно перебудовуються.
Так, Auto Layout з динамічним типом вимагає використання intrinsicContentSize у UILabel та UIButton. При accessibility-розмірах текст може виходити за межі superview — додайте UIScrollView або збільште leading/trailing constraints. Використовуйте UIFontMetrics.scaledValue для відступів (padding), щоб міжлітерні інтервали теж масштабувалися пропорційно шрифту.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.