Уявіть: користувач зі слабким зором збільшує шрифт на Android до 1.6x або навіть 2.0x, а ваш додаток перетворюється на кашу — тексти налізають один на одного, кнопки переміщуються або зникають. Ми стикалися з цим десятки разів. Типовий випадок: Samsung Galaxy S10, масштаб 1.6x — у картці замовлення текст обрізаний наполовину, кнопка «Оплатити» недоступна. Причина? Фіксовані висоти контейнерів і використання dp замість sp. Після нашого аудиту та доопрацювання (заміна layout, тести) додаток витримав fontScale 2.0 без жодної поломки.
Android дозволяє змінювати масштаб шрифту в Settings → Display → Font Size. Діапазон: від 0.85x до 2.0x (на стоковому Android). На Samsung One UI — до 1.6x в стандартному UI, але fontScale в Configuration може сягати 2.0x. Одиниці sp масштабуються, dp — ні. Ігнорування цього — головна причина проблем з доступністю.
Чому потрібен аудит масштабування шрифтів?
Без аудиту ви ризикуєте відштовхнути 15-20% користувачів, які змінюють масштаб. Наприклад, за статистикою Google, 1 з 8 людей має ослаблений зір. Крім того, Google Play Store вимагає дотримання доступності; порушення може призвести до відхилення оновлень.
Ми провели більше 50 проектів з адаптації під великі шрифти на Android. У нашій практиці був клієнт — агрегатор таксі — який втратив 30% конверсії на екрані замовлення через те, що користувачі з масштабом 1.4x не могли прочитати час прибуття. Ми виправили layout за 3 дні, і конверсія відновилася.
Як правильно використовувати sp і dp?
android:textSize="16sp" — коректно, шрифт масштабується. android:textSize="16dp" — не масштабується. Хардкод у dp — одна з найчастіших помилок. У Compose: fontSize = 16.sp — масштабується, fontSize = 16.dp — Lint видасть помилку компіляції починаючи з Compose 1.3. Однак TextUnit.Unspecified у кастомних компонентах — знову проблема.
| Одиниця | Масштабується | Рекомендація |
|---|---|---|
| sp | Так | Використовувати для тексту |
| dp | Ні | Для відступів, розмірів не тексту |
У чому відмінність? При fontScale 2.0 16sp перетворюється на 32sp (пікселі подвоюються), а 16dp залишається 16dp. Якщо ви задали висоту контейнера в dp, текст вилізе назовні. Порівняйте: wrap_content адаптується до будь-якого масштабу, тоді як фіксована висота ламається при fontScale 1.6 вже у 80% випадків.
Чому фіксована висота контейнерів — проблема?
Найчастіша помилка: android:layout_height="48dp" на TextView або контейнері з текстом. При fontScale = 2.0 текст розміром 16sp займає ~64dp висоти. Контейнер у 48dp обрізає вміст. Правильне рішення: wrap_content для висоти всіх текстових елементів. Для ConstraintLayout — прибрати фіксовану висоту у ланцюжків з текстом.
minHeight можна залишити для touch target (мінімум 48dp за Material Design) — але тільки через minHeight, не height.
Рядки з вставками
String.format("Ви заробили %d очок", points) — при довгому числі рядок подовжується. Але проблема не в числі, а у фіксованому layout навколо. ConstraintLayout з wrap_content справляється; вкладені LinearLayout з gravity — ні.
Compose: LocalDensity і масштаб
У Jetpack Compose LocalDensity містить і density (DPI), і fontScale. Якщо вручну конвертувати розміри через density.density без урахування fontScale — кастомні компоненти з TextUnit-розрахунками не масштабуються.
with(LocalDensity.current) { 16.sp.toPx() } — повертає пікселі вже з урахуванням fontScale. Якщо використовуєте це значення як висоту Canvas — все добре. Якщо ігноруєте і задаєте фіксований height у Modifier — ні.
Як локально вимкнути масштабування для декоративних елементів?
Для декоративних елементів у Compose можна використовувати CompositionLocalProvider(LocalDensity provides density), де density — копія з fontScale = 1f. Це корисно для логотипів або іконок, які не повинні змінюватися. Однак застосовуйте обережно: користувач очікує, що весь інтерфейс масштабується.
Наш досвід: кейс з масштабуванням 2.0
З нашої практики: клієнт-агрегатор таксі. При масштабі шрифту 1.6x на популярних моделях тексти в картці водія налізали один на одного. Ми діагностували проблему: всі LinearLayout всередині ScrollView мали фіксовану висоту. Замінили їх на ConstraintLayout з wrap_content, а для touch target залишили minHeight. Результат — додаток пройшов тести при fontScale 2.0. Порівняння: до доопрацювання текст обрізався на 50%, після — повністю читабельний.
Як ми тестуємо масштабування?
Використовуємо покроковий підхід:
- Встановлюємо fontScale 2.0 через ADB:
adb shell settings put system font_scale 2.0. - Візуально перевіряємо кожен екран на предмет перекриттів та обрізання.
- Запускаємо Espresso snapshot-тести з
Configuration.fontScale = 2fдля автоматичної регресії.
Android Studio Device Emulator: Pixel 6 з fontScale 2.0 — перший стенд. Реальний Samsung з One UI — другий стенд, там поведінка відрізняється.
| Інструмент | Метод | Особливості |
|---|---|---|
| ADB | settings put system font_scale 2.0 | Швидко, без перезапуску |
| Espresso | Configuration.fontScale = 2f | Для автоматичних тестів |
| Фізичний пристрій | Налаштування → Шрифт | Реалістичний сценарій |
Що входить у послугу?
- Аудит екранів на коректне масштабування (перевірка sp/dp, висот контейнерів, вставок)
- Виправлення layout: заміна фіксованих висот на wrap_content, оптимізація ConstraintLayout
- Для Compose: корекція LocalDensity, локальне вимкнення масштабу для декоративних елементів
- Налаштування тестів: ADB-скрипти та Espresso snapshot-тести
- Документація по підтримуваних екранах та обмеженнях
- Гарантія: після доопрацювання додаток коректно відображається при fontScale від 0.85 до 2.0
Терміни та вартість
Термін: від 2 до 3 днів на типовий додаток (10–20 екранів). Вартість розраховується індивідуально. Замовте аудит підтримки масштабування шрифтів — забезпечимо зручність для користувачів з ослабленим зором. Отримайте консультацію та комерційну пропозицію. Наш аудит допомагає заощадити бюджет на переробку після відхилення в маркеті.







