sp — Scale-independent Pixels, unitatea de măsură a textului în Android, care ia în considerare setările de dimensiune a fontului pe dispozitiv. Spre deosebire de dp, sp se scalează odată cu dimensiunea sistemului de font, asigurând accesibilitatea interfețelor. Articolul explică diferența dintre sp și dp, arată configurarea textSize în XML și Kotlin și dezvăluie cele mai bune practici de lucru cu tipografia în Android.
Principalele
sp (scale-independent pixel) — unitatea de măsură a dimensiunii fontului în Android, care se scalează automat în conformitate cu setările de sistem ale utilizatorului. Când proprietarul dispozitivului mărește dimensiunea fontului în setări, toate elementele cu valori în sp cresc proporțional. Aceasta asigură accesibilitatea interfeței pentru persoanele cu vedere slabă.
Relația de bază: 1 sp = 1 dp la scala standard a fontului 1.0 (normal). Dacă utilizatorul setează fontul Large (1.15×), 16 sp se transformă în 18.4 pixeli fizici. La dimensiunea fontului Small (0.85×), aceleași 16 sp vor deveni 13.6 px. Mecanismul de scalare este gestionat prin Settings.System.FONT_SCALE la nivelul Android Framework.
Conform Google Material Design Guidelines, textul trebuie setat exclusiv în sp. Excepție — etichetele fixe în componente unde dimensiunea este critică pentru compunere (de exemplu, textul din interiorul butoanelor cu înălțime fixă). În astfel de cazuri se recomandă utilizarea dp cu control manual al accesibilității.
Diferența dintre sp și dp — unul dintre cele mai frecvente subiecte de întrebări la interviurile pentru Android-developeri și în code review-uri reale. Ambele unități sunt legate de density-independent pixel (160 dpi = 1 dp = 1 px pe ecran mdpi), dar se comportă diferit la modificarea dimensiunii sistemului de font.
| Caracteristică | sp | dp |
|---|---|---|
| Destinație | Dimensiunea textului | Dimensiunile elementelor, distanțe, lățime, înălțime |
| Scalare după font | Da (scale factor) | Nu |
| Scalare după densitate | Da | Da |
| API pentru setare | android:textSize | android:layout_width, layout_height, padding, margin |
| Material Design Token | typescale | spacing, sizing |
În practică, greșeala — utilizarea dp pentru text. Dacă textul este setat în dp, nu se scalează la mărirea fontului, ceea ce face interfața inaccesibilă pentru utilizatorii cu vedere slabă. Greșeala inversă — utilizarea sp pentru înălțimea butonului sau distanțe: la mărirea fontului, butonul se poate „umfla", stricând compunerea.
Scalarea sp este implementată la nivelul Android Framework în clasa TypedValue. Formula de recalculare: sp = dp × scaledDensity, unde scaledDensity este coeficientul de scară care ia în considerare atât densitatea ecranului, cât și setarea fontului utilizatorului.
// Obținerea programatică a scaledDensity în Kotlin
val scaledDensity = with(context.resources) {
displayMetrics.scaledDensity
}
// Conversia sp în px
fun spToPx(sp: Float, context: Context): Float {
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP,
sp,
context.resources.displayMetrics
)
}
// Conversia px în sp
fun pxToSp(px: Float, context: Context): Float {
return px / context.resources.displayMetrics.scaledDensity
}Metoda TypedValue.applyDimension — singura modalitate corectă de conversie a sp în pixeli în runtime. Înmulțirea directă cu scaledDensity este mai puțin fiabilă, deoarece nu gestionează edge-case-urile (valori zero, depășire). scaledDensity se modifică la schimbarea setărilor fontului prin Settings > Display > Font size.
Android oferă cinci niveluri prestabilite de scară a fontului: Small (0.85×), Default (1.0×), Large (1.15×), Largest (1.3×) și un nivel suplimentar Very Large (>1.3×) în Android 14+. Producătorii de dispozitive (Samsung, Xiaomi) adaugă propriile niveluri — până la 2.0×. Dimensiunea minimă a textului în sp nu garantează niciodată un număr fix de pixeli.
În XML sp se aplică exclusiv în atributul android:textSize. Toate celelalte dimensiuni — width, height, padding, margin, elevation — se setează în dp. Regula este simplă: dacă elementul afișează text — dimensiunea sa în sp, dacă elementul definește geometria — dimensiunea în dp.
<!-- Aranjarea TextView cu textSize în 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" />
<!-- Utilizarea resurselor dimens -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="@dimen/text_body_large" />Se recomandă extragerea dimensiunilor textului în fișierul dimens.xml. Acest lucru simplifică întreținerea tipografiei, permite suprascrierea dimensiunilor pentru diferite configurații de ecran și asigură uniformitatea în întreaga aplicație.
<!-- 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 include 13 niveluri de dimensiuni — de la 11sp pentru etichete mici până la 57sp pentru titluri mari de afișare. Proiectele Android utilizează de obicei 8–10 niveluri. Toate valorile trebuie să fie multipli de 1sp — valorile fracționare (15.5sp) degradează randarea din cauza poziționării subpixel.
În dezvoltarea modernă Android, textul este rareori setat direct prin textSize în sp. În schimb, se utilizează sistemul MaterialTheme.typography, unde fiecare stil este predefinit și include dimensiunea, greutatea, spațierea între linii și letter-spacing.
// Tipografia personalizată prin 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
)
)Funcția de extensie .sp în Jetpack Compose se traduce automat în scale-independent pixels. La modificarea dimensiunii sistemului de font, Compose recalculează fontSize, lineHeight și spacing în conformitate cu noul scaledDensity. TextUnit (clasa care reprezintă sp) garantează că textul se scalează, iar distanțele — nu.
În Jetpack Compose sp este reprezentat de tipul TextUnit, care nu poate fi utilizat accidental pentru dimensiunile elementelor. Compilatorul Kotlin generează o eroare dacă TextUnit este transmis acolo unde se așteaptă Dp. Aceasta elimină o întreagă clasă de bug-uri legate de scalarea incorectă.
// TextUnit în Compose — lucrul sigur cu 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
)
}
}
// Setarea explicită a fontSize în sp
Text(
text = "Dimensiune personalizată",
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
color = MaterialTheme.colorScheme.primary
)În Compose nu există un echivalent direct al atributului XML android:textSize — dimensiunea textului se setează prin TextStyle.fontSize. Sistemul MaterialTheme.typography oferă stiluri predefinite care corespund Material Design Type Scale. Dacă este necesară o dimensiune personalizată, se utilizează literalul 20.sp — limbajul garantează că este TextUnit, nu Dp.
Utilizarea corectă a sp — baza unei aplicații Android accesibile. Mai jos sunt colectate reguli bazate pe recomandările Google Material Design și Android Developers Guide.
Regula principală a accesibilității: utilizatorul trebuie să aibă posibilitatea de a mări fontul fără a pierde funcționalitatea. Dacă aplicația funcționează corect la scala fontului 1.3×, va trece testele de bază de accessibility. Google Play poate respinge aplicația dacă textSize este setat în dp și interfața nu se scalează.
Întrebări frecvente
sp (scale-independent pixel) se scalează la modificarea dimensiunii sistemului de font, iar dp — nu. sp este utilizat doar pentru text, dp — pentru toate celelalte dimensiuni ale elementelor. Coeficientul de conversie: sp = dp × FONT_SCALE.
Nu. Distanțele, înălțimea butoanelor, lățimea cardurilor trebuie setate în dp. Utilizarea sp pentru distanțe duce la creșterea nefirească a elementelor la mărirea fontului, care pot ieși din limitele ecranului.
Deschideți Settings > Display > Font size și setați valoarea maximă (Largest). Lansați aplicația și verificați că tot textul este lizibil, elementele nu se suprapun, iar butoanele nu ies din limitele ecranului. Pentru automatizare, utilizați Espresso cu UiAutomator.
Material Design recomandă dimensiunea minimă 11sp pentru labelSmall. Pentru textul principal — de la 14sp (bodyMedium) la 16sp (bodyLarge). Dimensiunile mai mici de 11sp nu sunt recomandate, deoarece devin ilizibile pe dispozitivele cu densitate mare de pixeli.
Textul va fi afișat în dimensiune fixă independent de setările sistemului de font. Utilizatorii cu font mărit nu vor putea citi confortabil un astfel de text. Aceasta încalcă cerințele de accesibilitate WCAG și poate fi motiv de respingere a aplicației în Google Play.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și