sp — Scale-independent Pixels, unidade de medida de texto no Android que leva em conta as configurações de tamanho de fonte do dispositivo. Ao contrário do dp, o sp escala com o tamanho da fonte do sistema, garantindo a acessibilidade das interfaces. Este artigo explica a diferença entre sp e dp, mostra como configurar textSize em XML e Kotlin, e revela as melhores práticas para trabalhar com tipografia no Android.
Pontos Principais
sp (scale-independent pixel) — unidade de medida de tamanho de fonte no Android que escala automaticamente de acordo com as configurações do sistema do usuário. Quando o dono do dispositivo aumenta o tamanho da fonte nas configurações, todos os elementos com valores em sp crescem proporcionalmente. Isso garante a acessibilidade da interface para pessoas com deficiência visual.
A proporção básica: 1 sp = 1 dp na escala de fonte padrão 1.0 (normal). Se o usuário configurar a fonte como Grande (1.15×), 16 sp se tornam 18.4 pixels físicos. No tamanho de fonte Pequeno (0.85×), os mesmos 16 sp se tornam 13.6 px. O mecanismo de escalonamento é gerenciado através de Settings.System.FONT_SCALE no nível do Android Framework.
De acordo com as Google Material Design Guidelines, o texto deve ser especificado exclusivamente em sp. A exceção são rótulos fixos em componentes onde o tamanho é crítico para o layout (por exemplo, texto dentro de botões de altura fixa). Nesses casos, é recomendado usar dp com controle manual de acessibilidade.
A diferença entre sp e dp é um dos tópicos mais comuns em entrevistas de desenvolvedores Android e em revisões de código reais. Ambas as unidades estão vinculadas a pixels independentes de densidade (160 dpi = 1 dp = 1 px em telas mdpi), mas se comportam de maneira diferente quando o tamanho da fonte do sistema muda.
| Característica | sp | dp |
|---|---|---|
| Propósito | Tamanho do texto | Dimensões de elementos, padding, largura, altura |
| Escalonamento de fonte | Sim (fator de escala) | Não |
| Escalonamento de densidade | Sim | Sim |
| API de configuração | android:textSize | android:layout_width, layout_height, padding, margin |
| Token do Material Design | typescale | spacing, sizing |
Na prática, um erro comum é usar dp para texto. Se o texto for definido em dp, ele não escala quando o tamanho da fonte aumenta, tornando a interface inacessível para usuários com visão deficiente. O erro inverso é usar sp para altura de botão ou padding: quando a fonte aumenta, o botão pode "inflar", quebrando o layout.
O escalonamento de sp é implementado no nível do Android Framework na classe TypedValue. A fórmula de conversão é: sp = dp × scaledDensity, onde scaledDensity é um fator de escala que leva em conta tanto a densidade da tela quanto a configuração de fonte do usuário.
// Obtenção programática de scaledDensity em Kotlin
val scaledDensity = with(context.resources) {
displayMetrics.scaledDensity
}
// Conversão de sp para px
fun spToPx(sp: Float, context: Context): Float {
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP,
sp,
context.resources.displayMetrics
)
}
// Conversão de px para sp
fun pxToSp(px: Float, context: Context): Float {
return px / context.resources.displayMetrics.scaledDensity
}O método TypedValue.applyDimension é a única maneira correta de converter sp para pixels em tempo de execução. A multiplicação direta por scaledDensity é menos confiável pois não lida com casos extremos (valores zero, estouro). scaledDensity muda quando as configurações de fonte são modificadas via Settings > Display > Font size.
O Android fornece cinco níveis predefinidos de escala de fonte: Pequeno (0.85×), Padrão (1.0×), Grande (1.15×), Maior (1.3×) e um nível adicional Muito Grande (>1.3×) no Android 14+. Fabricantes de dispositivos (Samsung, Xiaomi) adicionam seus próprios níveis — até 2.0×. O tamanho mínimo de texto em sp nunca garante um número fixo de pixels.
Em layouts XML, sp é usado exclusivamente no atributo android:textSize. Todas as outras dimensões — largura, altura, padding, margem, elevação — são definidas em dp. A regra é simples: se o elemento exibe texto, seu tamanho é em sp; se o elemento define geometria, o tamanho é em dp.
<!-- Layout de TextView com textSize em 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" />
<!-- Uso de recursos dimens -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="@dimen/text_body_large" />É recomendado extrair os tamanhos de texto para um arquivo dimens.xml. Isso simplifica a manutenção da tipografia, permite sobrescrever tamanhos para diferentes configurações de tela e garante consistência em toda a aplicação.
<!-- 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 inclui 13 níveis de tamanho — de 11sp para rótulos pequenos a 57sp para grandes títulos de exibição. Projetos Android geralmente usam 8–10 níveis. Todos os valores devem ser múltiplos de 1sp — valores fracionários (15.5sp) degradam a renderização devido ao posicionamento de subpixels.
No desenvolvimento moderno de Android, o texto raramente é definido diretamente via textSize em sp. Em vez disso, é usado o sistema MaterialTheme.typography, onde cada estilo é predefinido e inclui tamanho, peso, altura da linha e espaçamento entre letras.
// Tipografia personalizada via 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
)
)A função de extensão .sp no Jetpack Compose se traduz automaticamente para pixels independentes de escala. Quando o tamanho da fonte do sistema muda, o Compose recalcula fontSize, lineHeight e spacing de acordo com a nova scaledDensity. TextUnit (a classe que representa sp) garante que o texto escala enquanto o padding não.
No Jetpack Compose, sp é representado pelo tipo TextUnit, que não pode ser usado acidentalmente para dimensões de elementos. O compilador Kotlin lançará um erro se TextUnit for passado onde Dp é esperado. Isso elimina toda uma classe de bugs relacionados ao escalonamento incorreto.
// TextUnit no Compose — trabalho seguro com 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
)
}
}
// Definição explícita de fontSize em sp
Text(
text = "Tamanho personalizado",
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
color = MaterialTheme.colorScheme.primary
)Compose não tem um equivalente direto do atributo XML android:textSize — o tamanho do texto é definido via TextStyle.fontSize. O sistema MaterialTheme.typography fornece estilos predefinidos que correspondem à Material Design Type Scale. Se um tamanho personalizado for necessário, o literal 20.sp é usado — a linguagem garante que isso é TextUnit, não Dp.
O uso correto de sp é a base de uma aplicação Android acessível. Abaixo estão regras baseadas nas recomendações do Google Material Design e Android Developers Guide.
A regra principal de acessibilidade: o usuário deve ser capaz de aumentar o tamanho da fonte sem perder funcionalidade. Se a aplicação funciona corretamente em uma escala de fonte de 1.3×, ela passará nos testes básicos de acessibilidade. O Google Play pode rejeitar a aplicação se textSize estiver definido em dp e a interface não escalar.
Perguntas Frequentes
sp (scale-independent pixel) escala quando o tamanho da fonte do sistema muda, enquanto dp não. sp é usado apenas para texto, dp para todas as outras dimensões de elementos. Fator de conversão: sp = dp × FONT_SCALE.
Não. Padding, altura de botões e largura de cartões devem ser definidos em dp. Usar sp para padding faz com que os elementos cresçam de forma não natural quando a fonte aumenta e podem ultrapassar os limites da tela.
Abra Settings > Display > Font size e defina o valor máximo (Largest). Inicie o aplicativo e verifique se todo o texto é legível, os elementos não se sobrepõem e os botões não ultrapassam os limites da tela. Para automação, use Espresso com UiAutomator.
Material Design recomenda um tamanho mínimo de 11sp para labelSmall. Para texto do corpo — de 14sp (bodyMedium) a 16sp (bodyLarge). Tamanhos menores que 11sp não são recomendados pois se tornam ilegíveis em dispositivos com alta densidade de pixels.
O texto será exibido em um tamanho fixo independentemente das configurações de fonte do sistema. Usuários com fontes ampliadas não conseguirão ler esse texto confortavelmente. Isso viola os requisitos de acessibilidade WCAG e pode causar a rejeição do aplicativo no Google Play.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também