sp — Scale-independent Pixels, jednotka měření textu v Androidu, která zohledňuje nastavení velikosti písma na zařízení. Na rozdíl od dp se sp škáluje spolu s velikostí systémového písma, což zajišťuje přístupnost rozhraní. Článek vysvětluje rozdíl mezi sp a dp, ukazuje nastavení textSize v XML a Kotlinu a odhaluje nejlepší postupy práce s typografií v Androidu.
Hlavní body
sp (scale-independent pixel) — jednotka měření velikosti písma v Androidu, která se automaticky škáluje podle systémového nastavení uživatele. Když majitel zařízení zvýší velikost písma v nastavení, všechny prvky s hodnotami sp proporcionálně rostou. To zajišťuje přístupnost rozhraní pro osoby se slabým zrakem.
Základní poměr: 1 sp = 1 dp při standardním měřítku písma 1.0 (normal). Pokud uživatel nastaví písmo Large (1.15×), 16 sp se přemění na 18.4 fyzických pixelů. Při velikosti písma Small (0.85×) se stejných 16 sp stane 13.6 px. Mechanismus škálování je řízen přes Settings.System.FONT_SCALE na úrovni Android Framework.
Podle Google Material Design Guidelines by měl být text nastavován výhradně v sp. Výjimkou jsou pevné popisky v komponentách, kde je velikost kritická pro rozvržení (např. text uvnitř tlačítek s pevnou výškou). V takových případech se doporučuje použití dp s ruční kontrolou přístupnosti.
Rozdíl mezi sp a dp — jedno z nejčastějších témat otázek na pohovorech pro Android vývojáře a v reálných code review. Obě jednotky jsou vázány na density-independent pixel (160 dpi = 1 dp = 1 px na mdpi obrazovce), ale chovají se odlišně při změně systémové velikosti písma.
| Vlastnost | sp | dp |
|---|---|---|
| Účel | Velikost textu | Rozměry prvků, mezery, šířka, výška |
| Škálování s písmem | Ano (scale factor) | Ne |
| Škálování s hustotou | Ano | Ano |
| API pro nastavení | android:textSize | android:layout_width, layout_height, padding, margin |
| Material Design Token | typescale | spacing, sizing |
V praxi chyba — použití dp pro text. Pokud je text nastaven v dp, neškáluje se při zvětšení písma, což činí rozhraní nepřístupným pro uživatele se slabým zrakem. Opačná chyba — použití sp pro výšku tlačítka nebo mezery: při zvětšení písma se tlačítko může „nafouknout", čímž se rozbije rozvržení.
Škálování sp je implementováno na úrovni Android Framework ve třídě TypedValue. Vzorec přepočtu: sp = dp × scaledDensity, kde scaledDensity je koeficient měřítka zohledňující jak hustotu obrazovky, tak nastavení písma uživatele.
// Programové získání scaledDensity v Kotlinu
val scaledDensity = with(context.resources) {
displayMetrics.scaledDensity
}
// Převod sp na px
fun spToPx(sp: Float, context: Context): Float {
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP,
sp,
context.resources.displayMetrics
)
}
// Převod px na sp
fun pxToSp(px: Float, context: Context): Float {
return px / context.resources.displayMetrics.scaledDensity
}Metoda TypedValue.applyDimension — jediný správný způsob konverze sp na pixely za běhu. Přímé násobení scaledDensity je méně spolehlivé, protože nezpracovává okrajové případy (nulové hodnoty, přetečení). scaledDensity se mění při změně nastavení písma přes Settings > Display > Font size.
Android poskytuje pět přednastavených úrovní měřítka písma: Small (0.85×), Default (1.0×), Large (1.15×), Largest (1.3×) a další úroveň Very Large (>1.3×) v Android 14+. Výrobci zařízení (Samsung, Xiaomi) přidávají vlastní úrovně — až do 2.0×. Minimální velikost textu v sp nikdy nezaručuje pevný počet pixelů.
V XML se sp používá výhradně v atributu android:textSize. Všechny ostatní rozměry — width, height, padding, margin, elevation — se nastavují v dp. Pravidlo je jednoduché: pokud prvek zobrazuje text — jeho velikost v sp, pokud prvek definuje geometrii — velikost v dp.
<!-- Rozvržení TextView s textSize v 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" />
<!-- Použití dimens zdrojů -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="@dimen/text_body_large" />Doporučuje se vyjímat velikosti textu do souboru dimens.xml. To zjednodušuje údržbu typografie, umožňuje přepisovat velikosti pro různé konfigurace obrazovky a zajišťuje jednotnost v celé aplikaci.
<!-- 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 zahrnuje 13 úrovní velikostí — od 11sp pro malé popisky po 57sp pro velké zobrazovací nadpisy. Android projekty obvykle používají 8–10 úrovní. Všechny hodnoty by měly být násobky 1sp — zlomkové hodnoty (15.5sp) zhoršují vykreslování kvůli subpixelovému umístění.
V moderním vývoji Android je text zřídka nastavován přímo přes textSize v sp. Místo toho se používá systém MaterialTheme.typography, kde je každý styl předdefinován a zahrnuje velikost, váhu, řádkování a letter-spacing.
// Vlastní typografie přes 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
)
)Rozšiřující funkce .sp v Jetpack Compose se automaticky překládá na scale-independent pixely. Při změně systémové velikosti písma Compose přepočítává fontSize, lineHeight a spacing podle nového scaledDensity. TextUnit (třída reprezentující sp) zaručuje, že se text škáluje, zatímco mezery — ne.
V Jetpack Compose je sp reprezentován typem TextUnit, který nelze náhodně použít pro rozměry prvků. Kotlin kompilátor hlásí chybu, pokud je TextUnit předán tam, kde se očekává Dp. To eliminuje celou třídu chyb souvisejících s nesprávným škálováním.
// TextUnit v Compose — bezpečná práce se 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
)
}
}
// Explicitní nastavení fontSize v sp
Text(
text = "Vlastní velikost",
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
color = MaterialTheme.colorScheme.primary
)V Compose neexistuje přímý ekvivalent XML atributu android:textSize — velikost textu se nastavuje přes TextStyle.fontSize. Systém MaterialTheme.typography poskytuje předdefinované styly, které odpovídají Material Design Type Scale. Pokud je potřeba vlastní velikost, použije se literál 20.sp — jazyk zaručuje, že se jedná o TextUnit, nikoli Dp.
Správné použití sp — základ přístupné Android aplikace. Níže jsou shromážděna pravidla založená na doporučeních Google Material Design a Android Developers Guide.
Hlavní pravidlo přístupnosti: uživatel by měl mít možnost zvětšit písmo bez ztráty funkčnosti. Pokud aplikace funguje správně při měřítku písma 1.3×, projde základními testy přístupnosti. Google Play může aplikaci odmítnout, pokud je textSize nastaven v dp a rozhraní se neškáluje.
Často kladené otázky
sp (scale-independent pixel) se škáluje při změně systémové velikosti písma, zatímco dp — ne. sp se používá pouze pro text, dp — pro všechny ostatní rozměry prvků. Přepočítací koeficient: sp = dp × FONT_SCALE.
Ne. Mezery, výška tlačítek, šířka karet by měly být nastaveny v dp. Použití sp pro mezery vede k nepřirozenému růstu prvků při zvětšení písma a mohou přesahovat okraje obrazovky.
Otevřete Settings > Display > Font size a nastavte maximální hodnotu (Largest). Spusťte aplikaci a zkontrolujte, že veškerý text je čitelný, prvky se nepřekrývají a tlačítka nepřesahují okraje obrazovky. Pro automatizaci použijte Espresso s UiAutomator.
Material Design doporučuje minimální velikost 11sp pro labelSmall. Pro hlavní text — od 14sp (bodyMedium) do 16sp (bodyLarge). Velikosti menší než 11sp se nedoporučují, protože se stávají nečitelnými na zařízeních s vysokou hustotou pixelů.
Text se bude zobrazovat v pevné velikosti nezávisle na systémovém nastavení písma. Uživatelé se zvětšeným písmem nebudou moci takový text pohodlně číst. To porušuje požadavky přístupnosti WCAG a může být důvodem odmítnutí aplikace v Google Play.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také