В чем разница между px, dp и sp?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
В чем разница между px, dp и sp
Это три разных единицы измерения в Android, которые используются для разных целей. Понимание разницы критично для создания адаптивных приложений, которые хорошо выглядят на устройствах с разными размерами экранов и плотностью пикселей.
px (Pixel)
px — это физический пиксель, абсолютная единица, привязанная к экрану. 1 px = 1 пиксель на экране.
Проблема:
- На устройствах с разной плотностью пикселей (DPI/PPI) элементы выглядят по-разному
- Экран с 150 DPI и 400 DPI с одинаковым px размером будут выглядеть очень по-разному
- Невозможно создать адаптивный дизайн
// Плохо: не адаптивно
val view = TextView(this)
view.width = 200 // 200 пиксель - на разных устройствах разные размеры
Когда использовать px:
- Почти никогда в реальных приложениях
- Только для специальных случаев (draw операции, custom painting)
- Для 1px бордюров (border в canvas)
dp (Density-Independent Pixel)
dp (или dip — Density Independent Pixel) — это логическая единица, которая масштабируется на основе плотности экрана.
Как это работает:
- Система конвертирует dp в пиксели на основе DPI экрана
- 1 dp = 1 пиксель на экране с плотностью 160 dpi (baseline)
1 dp = (screenDensity / 160) * 1 px
Примеры расчётов:
- На экране 160 dpi: 1 dp = 1 px
- На экране 320 dpi (2x плотность): 1 dp = 2 px
- На экране 480 dpi (3x плотность): 1 dp = 3 px
Как получить density:
val density = context.resources.displayMetrics.density
val dpInPx = (16 * density).toInt() // Конвертируем 16 dp в пиксели
Когда использовать dp:
- Всегда для размеров элементов (width, height, padding, margin)
- Для бордюров
- Для расстояний между элементами
- Для иконок
// Хорошо: адаптивно на всех устройствах
val button = Button(this)
button.width = 200.dp // Специальный extension
button.height = 48.dp
// Или в XML
<Button
android:layout_width="200dp"
android:layout_height="48dp"
android:padding="16dp"
android:layout_margin="8dp" />
sp (Scale-independent Pixel)
sp (Scale-independent Pixel) — это то же самое, что dp, но ПЛЮС масштабируется на основе настроек размера шрифта пользователя.
Как это работает:
1 sp = (screenDensity / 160) * userFontScale
userFontScale по умолчанию = 1.0, но пользователь может изменить размер шрифта в настройках (Small, Normal, Large, Extra Large).
Пример:
- Нормальный размер (100%): 1 sp = 1 dp
- Большой размер (125%): 1 sp = 1.25 dp
- Очень большой (200%): 1 sp = 2.0 dp
Когда использовать sp:
- ВСЕГДА для размера текста (android:textSize)
- Никогда для других размеров
// Хорошо: размер шрифта будет масштабироваться вместе с пользовательскими настройками
val textView = TextView(this)
textView.textSize = 16f // По умолчанию в sp
// В XML
<TextView
android:textSize="16sp"
android:text="Hello World" />
Наглядное сравнение
| Единица | Адаптивная | User Font Scale | Используется для | Пример |
|---|---|---|---|---|
| px | Нет | Нет | Очень редко (draw, border) | 1px line |
| dp | Да | Нет | Размеры, отступы, иконки | Button width: 200dp |
| sp | Да | Да | Размер текста | TextView textSize: 16sp |
Практический пример
// ✅ Правильно
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"> // Отступ внутри
<ImageView
android:layout_width="48dp" // Размер иконки
android:layout_height="48dp"
android:src="@drawable/ic_home" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp" // Размер шрифта
android:layout_marginStart="8dp" // Отступ элемента
android:text="Home" />
</LinearLayout>
// ❌ Неправильно
<LinearLayout
android:padding="16px"> // Не адаптивно
<ImageView
android:layout_width="48px" // Очень неправильно для иконки
android:layout_height="48px" />
<TextView
android:textSize="16dp" /> // Размер шрифта должен быть в sp
</LinearLayout>
Как конвертировать в коде
// Extension функции для удобства
val Int.dp: Int get() = (this * Resources.getSystem().displayMetrics.density).toInt()
val Int.sp: Float get() = this * Resources.getSystem().displayMetrics.scaledDensity
// Использование
val paddingInPx = 16.dp // Конвертируем 16dp в пиксели
val textSize = 16.sp // Конвертируем 16sp в пиксели
view.setPadding(16.dp, 16.dp, 16.dp, 16.dp)
textView.textSize = 16f // по умолчанию в sp
Ключевое правило
Простое правило для запоминания:
- dp = для всего визуального (размеры, отступы, иконки)
- sp = только для текста
- px = никогда не используй в приложениях
Это позволяет приложению автоматически масштабироваться на устройствах с разной плотностью пиксели и учитывает пожелания пользователя по размеру шрифта.