sp — Scale-independent Pixels, јединица мере текста у Android-у која узима у обзир подешавања величине фонта на уређају. За разлику од dp, sp се скалира заједно са системским фонтом, обезбеђујући приступачност интерфејса. Чланак објашњава разлику између sp и dp, приказује подешавање textSize у XML и Kotlin-у, као и открива најбоље праксе рада са типографијом у Android-у.
Главно
sp (scale-independent pixel) — јединица мере величине фонта у Android-у која се аутоматски скалира у складу са системским подешавањима корисника. Када власник уређаја повећа величину фонта у подешавањима, сви елементи са вредностима у sp пропорционално расту. Ово обезбеђује приступачност интерфејса за особе са слабим видом.
Основна релација: 1 sp = 1 dp при стандардној скали фонта 1.0 (normal). Ако корисник постави фонт Large (1.15×), 16 sp се претвара у 18.4 физичка пиксела. При величини фонта Small (0.85×) истих 16 sp постаће 13.6 px. Механизам скалирања се управља преко Settings.System.FONT_SCALE на нивоу Android Framework-а.
Према Google Material Design Guidelines, текст треба постављати искључиво у sp. Изузетак — фиксне ознаке у компонентама где је величина критична за распоред (нпр. текст унутар дугмади фиксне висине). У таквим случајевима препоручује се коришћење dp са ручном контролом приступачности.
Разлика између sp и dp — једна од најчешћих тема питања на интервјуима за Android-developere и у стварним code review-има. Обе јединице су везане за density-independent pixel (160 dpi = 1 dp = 1 px на mdpi екрану), али се понашају другачије при промени системског фонта.
| Карактеристика | sp | dp |
|---|---|---|
| Намена | Величина текста | Димензије елемената, размаци, ширина, висина |
| Скалирање према фонту | Да (scale factor) | Не |
| Скалирање према густини | Да | Да |
| API за постављање | android:textSize | android:layout_width, layout_height, padding, margin |
| Material Design Token | typescale | spacing, sizing |
У пракси грешка — коришћење dp за текст. Ако је текст постављен у dp, не скалира се при повећању фонта, што чини интерфејс недоступним за кориснике са слабим видом. Обрнута грешка — коришћење sp за висину дугмета или размаке: при повећању фонта дугме може да се „надува", покваривши распоред.
Скалирање sp је имплементирано на нивоу Android Framework-а у класи TypedValue. Формула прерачунавања: sp = dp × scaledDensity, где је scaledDensity коефицијент скале који узима у обзир и густину екрана и подешавање фонта корисника.
// Програмско добијање scaledDensity у Kotlin-у
val scaledDensity = with(context.resources) {
displayMetrics.scaledDensity
}
// Конверзија sp у px
fun spToPx(sp: Float, context: Context): Float {
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP,
sp,
context.resources.displayMetrics
)
}
// Конверзија px у sp
fun pxToSp(px: Float, context: Context): Float {
return px / context.resources.displayMetrics.scaledDensity
}Метод TypedValue.applyDimension — једини исправан начин конверзије sp у пикселе у runtime-у. Директно множење са scaledDensity је мање поуздано, јер не обрађује edge-case-ове (нулте вредности, прекорачење). scaledDensity се мења при промени подешавања фонта преко Settings > Display > Font size.
Android пружа пет подешених нивоа скале фонта: Small (0.85×), Default (1.0×), Large (1.15×), Largest (1.3×) и додатни ниво Very Large (>1.3×) у Android 14+. Произвођачи уређаја (Samsung, Xiaomi) додају сопствене нивое — чак до 2.0×. Минимална величина текста у sp никада не гарантује фиксан број пиксела.
У XML-у sp се примењује искључиво у атрибуту android:textSize. Све остале димензије — width, height, padding, margin, elevation — постављају се у dp. Правило је једноставно: ако елемент приказује текст — његова величина у sp, ако елемент дефинише геометрију — величина у dp.
<!-- Распоред TextView са textSize у sp -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
android:textSize="16sp"
android:padding="12dp"
android:lineSpacingExtra="4dp" />
<!-- Коришћење dimens ресурса -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="@dimen/text_body_large" />Препоручује се издвајање величина текста у датотеку dimens.xml. Ово поједностављује одржавање типографије, омогућава преписивање величина за различите конфигурације екрана и обезбеђује једнообразност у целој апликацији.
<!-- res/values/dimens.xml -->
<resources>
<!-- Material Design Type Scale -->
<dimen name="text_display_large">34sp</dimen>
<dimen name="text_display_medium">28sp</dimen>
<dimen name="text_headline_large">24sp</dimen>
<dimen name="text_headline_medium">20sp</dimen>
<dimen name="text_title_large">18sp</dimen>
<dimen name="text_body_large">16sp</dimen>
<dimen name="text_body_medium">14sp</dimen>
<dimen name="text_label_large">14sp</dimen>
<dimen name="text_label_small">11sp</dimen>
</resources>Material Design Type Scale укључује 13 нивоа величина — од 11sp за мале ознаке до 57sp за велике дисплеј наслове. Android пројекти обично користе 8–10 нивоа. Све вредности треба да буду умножци од 1sp — разломљене вредности (15.5sp) погоршавају рендеровање због субпикселског позиционирања.
У модерном Android развоју текст се ретко поставља директно преко textSize у sp. Уместо тога користи се систем MaterialTheme.typography, где је сваки стил унапред дефинисан и укључује величину, тежину, размак између редова и letter-spacing.
// Прилагођена типографија преко Typography API
val AppTypography = Typography(
displayLarge = TextStyle(
fontWeight = FontWeight.Normal,
fontSize = 34.sp,
lineHeight = 40.sp,
letterSpacing = 0.sp
),
headlineLarge = TextStyle(
fontWeight = FontWeight.SemiBold,
fontSize = 24.sp,
lineHeight = 32.sp
),
titleLarge = TextStyle(
fontWeight = FontWeight.Medium,
fontSize = 18.sp,
lineHeight = 24.sp
),
bodyLarge = TextStyle(
fontWeight = FontWeight.Normal,
fontSize = 16.sp,
lineHeight = 24.sp,
letterSpacing = 0.5.sp
),
labelSmall = TextStyle(
fontWeight = FontWeight.Medium,
fontSize = 11.sp,
lineHeight = 16.sp,
letterSpacing = 0.5.sp
)
)Функција проширења .sp у Jetpack Compose-у се аутоматски преводи у scale-independent pixels. При промени системске величине фонта, Compose прерачунава fontSize, lineHeight и spacing у складу са новим scaledDensity. TextUnit (класа која представља sp) гарантује да се текст скалира, а размаци — не.
У Jetpack Compose-у sp је представљен типом TextUnit, који не може бити случајно коришћен за димензије елемената. Kotlin компајлер пријављује грешку ако се TextUnit проследи тамо где се очекује Dp. Ово елиминише читаву класу грешака повезаних са неправилним скалирањем.
// TextUnit у Compose-у — безбедан рад са sp
@Composable
fun ArticleCard(title: String, description: String) {
Card(modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
Text(
text = title,
style = MaterialTheme.typography.titleLarge
)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = description,
style = MaterialTheme.typography.bodyMedium
)
}
}
// Експлицитно постављање fontSize у sp
Text(
text = "Прилагођена величина",
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
color = MaterialTheme.colorScheme.primary
)У Compose-у не постоји директни еквивалент XML атрибута android:textSize — величина текста се поставља преко TextStyle.fontSize. Sistem MaterialTheme.typography пружа унапред дефинисане стилове који одговарају Material Design Type Scale. Ако је потребна прилагођена величина, користи се литерал 20.sp — језик гарантује да је то TextUnit, а не Dp.
Исправно коришћење sp — основа приступачне Android апликације. Испод су сакупљена правила заснована на препорукама Google Material Design и Android Developers Guide.
Главно правило приступачности: корисник треба да има могућност повећања фонта без губитка функционалности. Ако апликација исправно ради при скали фонта 1.3×, проћи ће основне тестове accessibility. Google Play може одбити апликацију ако је textSize постављен у dp и интерфејс се не скалира.
Често постављана питања
sp (scale-independent pixel) се скалира при промени системске величине фонта, а dp — не. sp се користи само за текст, dp — за све остале димензије елемената. Коефицијент прерачуна: sp = dp × FONT_SCALE.
Не. Размаци, висина дугмади, ширина картица треба да се постављају у dp. Коришћење sp за размаке доводи до тога да при повећању фонта елементи расту неприродно и могу излазити изван граница екрана.
Отворите Settings > Display > Font size и поставите максималну вредност (Largest). Покрените апликацију и проверите да је сав текст читак, елементи се не преклапају, а дугмад не излазе ван граница екрана. За аутоматизацију користите Espresso са UiAutomator-ом.
Material Design препоручује минималну величину 11sp за labelSmall. За главни текст — од 14sp (bodyMedium) до 16sp (bodyLarge). Величине мање од 11sp се не препоручују, јер постају нечитке на уређајима са високом густином пиксела.
Текст ће се приказивати у фиксној величини независно од системских подешавања фонта. Корисници са увећаним фонтом неће моћи удобно да читају такав текст. Ово крши захтеве приступачности WCAG и може бити разлог одбијања апликације у Google Play-у.
Резиме
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође