SpannableString: o que é, classes de estilo e como funciona

Autor: IT Sectr Publicado: 2026-07-23 Tempo de leitura: 10 min

SpannableString é uma classe do Android SDK do pacote android.text que permite aplicar vários estilos a diferentes partes de uma mesma string de texto no TextView. Ao contrário da marcação HTML, o SpannableString trabalha no nível de objetos Span, controlando a exibição visual do texto: cor, tamanho, tipo de letra, sublinhado e elementos interativos. De acordo com o Google Developers, o SpannableString é usado em componentes do sistema Android para formatar links. É a principal forma de estilizar texto sem usar bibliotecas de terceiros.

Pontos Principais

  • SpannableString — uma classe Android para estilizar texto através de objetos Span, imutável após a criação
  • Spans são divididos em CharacterStyle (caracteres individuais) e ParagraphStyle (parágrafos inteiros)
  • ForegroundColorSpan muda a cor do texto, StyleSpan lida com negrito e itálico
  • SpannableStringBuilder — uma versão mutável para construção dinâmica de texto com suporte a Editable
  • Flags de Span determinam o comportamento do span ao inserir ou excluir texto nos limites do intervalo

O que é SpannableString?

SpannableString é uma classe Android que implementa a interface Spannable, armazenando texto juntamente com um conjunto de objetos Span que controlam a exibição visual. Ao contrário de uma String comum, SpannableString permite anexar atributos de estilo a intervalos específicos de caracteres: tornar parte do texto vermelha, aumentar o tamanho da fonte em um título ou adicionar um link clicável dentro de um parágrafo.

A classe está no pacote android.text e está disponível desde a API Level 1. SpannableString é imutável — uma vez criada, sua estrutura é fixa e substituir texto requer a criação de um novo objeto. Para edição dinâmica, usa-se SpannableStringBuilder, que suporta inserção e exclusão de caracteres sem perder estilos.

Diferença do CharSequence

CharSequence é a interface base para dados de texto, implementada por String, StringBuilder e SpannableString. A principal diferença entre SpannableString e String é o suporte para anexar objetos arbitrários a uma substring. O TextView reconhece a interface Spannable e aplica os objetos span aos segmentos de texto correspondentes durante a renderização. Se você passar uma String comum para TextView, nenhum estilo será aplicado.

Estrutura Interna

SpannableString armazena texto como um array char[] e um array separado de objetos span com metadados sobre as posições inicial e final. Quando setSpan(what, start, end, flags) é chamado, o objeto what é salvo na lista junto com as informações do intervalo. Durante a renderização, o TextView aplica sequencialmente todos os spans que estão dentro do intervalo exibido, chamando os métodos updateDrawState e updateMeasureState.

Tipos de Spans: CharacterStyle e ParagraphStyle

CharacterStyle é a classe base para spans que afetam caracteres individuais independentemente de sua posição nas linhas. Isso inclui ForegroundColorSpan (cor do texto), RelativeSizeSpan (tamanho relativo), StyleSpan (negrito e itálico), UnderlineSpan (sublinhado) e outros. Spans de caractere são aplicados a cada caractere no intervalo especificado individualmente.

ParagraphStyle é uma interface para spans que afetam parágrafos inteiros. O representante mais conhecido é AlignmentSpan, que alinha o parágrafo inteiro à esquerda, centro ou direita. Spans de parágrafo devem cobrir o parágrafo inteiro; caso contrário, o Android ignora sua aplicação. Essa limitação ocorre porque alinhamento ou recuo só fazem sentido para um bloco de texto completo.

Flags de Span

As flags de Span são quatro constantes que definem o comportamento do span ao inserir ou excluir texto nos limites de seu intervalo. SPAN_EXCLUSIVE_EXCLUSIVE mantém o span ativo apenas dentro dos limites originais, SPAN_INCLUSIVE_INCLUSIVE o estende ao adicionar texto nos limites. SPAN_EXCLUSIVE_INCLUSIVE e SPAN_INCLUSIVE_EXCLUSIVE fornecem comportamento misto para o início e o fim do intervalo.

FlagInserção à EsquerdaInserção à Direita
SPAN_EXCLUSIVE_EXCLUSIVEnão incluinão inclui
SPAN_INCLUSIVE_INCLUSIVEincluiinclui
SPAN_EXCLUSIVE_INCLUSIVEnão incluiinclui
SPAN_INCLUSIVE_EXCLUSIVEincluinão inclui

Escolher a flag correta é crítico para texto Editable no EditText, onde o usuário pode inserir e excluir caracteres. Para TextView somente leitura, geralmente se usa SPAN_EXCLUSIVE_EXCLUSIVE — o estilo se aplica apenas ao intervalo original e não se expande com alterações programáticas.

Principais Classes de Span no Android SDK

O Android SDK fornece mais de 25 classes de span incorporadas que cobrem a maioria das tarefas de estilo de texto. Cada classe implementa a interface CharacterStyle ou ParagraphStyle e aceita parâmetros através de seu construtor. Todas as classes estão no pacote android.text.style e estão disponíveis sem adicionar dependências extras.

Spans de Cor e Fundo

ForegroundColorSpan define a cor do texto para um intervalo especificado, aceitando uma cor no formato int. BackgroundColorSpan pinta o fundo atrás do texto, útil para destacar resultados de pesquisa. AbsoluteSizeSpan define um tamanho de fonte exato em pixels, RelativeSizeSpan aplica um multiplicador relativo ao tamanho base do texto no TextView.

Spans de Tipo de Letra

StyleSpan aceita as constantes Typeface.NORMAL, Typeface.BOLD, Typeface.ITALIC ou BOLD_ITALIC e altera o tipo de letra dos caracteres. UnderlineSpan adiciona sublinhado, StrikethroughSpan adiciona tachado. SuperscriptSpan e SubscriptSpan criam sobrescrito e subscrito. TypefaceSpan permite definir uma fonte personalizada através de um objeto Typeface para um intervalo de texto.

Spans Interativos

ClickableSpan é uma classe abstrata para criar segmentos de texto clicáveis. Ao tocar, o método onClick() é chamado. Para que os cliques funcionem, o TextView deve ter setMovementMethod(LinkMovementMethod.getInstance()). URLSpan é uma subclasse de ClickableSpan para hiperlinks com abertura automática do navegador. ClickableSpan é frequentemente combinado com ForegroundColorSpan para destacar visualmente o link em azul.

kotlin
val spannable = SpannableString("Open developer.android.com")
spannable.setSpan(
    URLSpan("https://developer.android.com"),
    9, 31, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
spannable.setSpan(
    ForegroundColorSpan(Color.BLUE),
    9, 31, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
textView.text = spannable
textView.movementMethod = LinkMovementMethod.getInstance()

Sem LinkMovementMethod, os cliques em URLSpan não serão processados. MovementMethod é responsável por interceptar eventos de toque e encontrar o ClickableSpan na posição do toque. O span de cor torna o link visível para o usuário.

Como Usar SpannableString no Código

Trabalhar com SpannableString começa criando uma instância a partir de uma string de texto e aplicando spans sequencialmente através do método setSpan(). O método aceita quatro parâmetros: o objeto span, a posição inicial, a posição final e as flags. Depois de definir todos os spans, o objeto é passado para TextView através de setText().

Cor e Tamanho do Texto

Vamos criar uma string onde a primeira palavra seja vermelha e ampliada. Para isso, usamos ForegroundColorSpan para a cor e RelativeSizeSpan para a escala. Ambos os spans são aplicados ao mesmo intervalo de forma independente — a ordem das chamadas setSpan não importa.

kotlin
val text = "Header: remaining text"
val spannable = SpannableString(text)
val colorSpan = ForegroundColorSpan(Color.RED)
val sizeSpan = RelativeSizeSpan(1.5f)
spannable.setSpan(colorSpan, 0, 9, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
spannable.setSpan(sizeSpan, 0, 9, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
textView.text = spannable

Os caracteres da posição 0 à 9 recebem ambos os estilos simultaneamente. O TextView aplica automaticamente todos os spans durante a renderização — nenhuma chamada adicional é necessária. RelativeSizeSpan com um multiplicador de 1.5f aumenta o tamanho da fonte em 50% em relação ao base.

Combinação com Tags HTML

Html.fromHtml() cria um objeto Spanned a partir de uma string HTML, mas o conjunto de tags suportadas é limitado. SpannableString dá controle total sobre cada atributo sem limitações de HTML. Se você precisar converter HTML em spans e depois adicionar estilos personalizados, pode usar Html.fromHtml() como base e depois complementar com spans através de setSpan().

kotlin
val htmlText = Html.fromHtml(
    "<b>Important:</b> check the data",
    Html.FROM_HTML_MODE_LEGACY
)
val spannable = SpannableString(htmlText)
spannable.setSpan(
    ForegroundColorSpan(Color.RED),
    0, 6, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
textView.text = spannable

O resultado — o texto “Importante:” estará em negrito (do HTML) e vermelho (do span). Essa abordagem é conveniente ao trabalhar com conteúdo de servidor onde parte da formatação é especificada em HTML e parte é adicionada no lado do cliente programaticamente.

Combinação de Múltiplos Spans

SpannableString permite aplicar um número ilimitado de spans ao mesmo intervalo ou a intervalos sobrepostos. Combinar spans é uma vantagem chave sobre a marcação HTML, onde tags aninhadas podem entrar em conflito. Os spans são independentes e aplicados sequencialmente durante a renderização.

Por exemplo, você pode tornar um segmento de texto simultaneamente em negrito, vermelho e clicável. Para fazer isso, crie três spans — StyleSpan, ForegroundColorSpan e ClickableSpan — e aplique cada um ao mesmo intervalo. A ordem de aplicação não afeta o resultado, pois cada span é responsável por seu próprio atributo de texto.

Sobreposição de Spans de Diferentes Tipos

Se spans de diferentes tipos se sobrepõem parcialmente, cada um funciona independentemente dentro de seus próprios limites. ForegroundColorSpan no intervalo 0–10 e StyleSpan(BOLD) no intervalo 5–15 darão texto vermelho em negrito no segmento 5–10 e apenas negrito no 10–15. Nenhum conflito surge porque cada span modifica seu próprio atributo durante a renderização.

Obtendo a Lista de Spans

O método getSpans(int start, int end, Class type) retorna um array de spans dentro do intervalo especificado. Isso é útil para verificar quais estilos já foram aplicados ou para remover spans específicos. Com nextSpanTransition(), você pode iterar sobre os limites de mudança de spans — esta é a base para implementações personalizadas de TextView que precisam saber onde o estilo muda.

SpannableStringBuilder para Construção de Texto

SpannableStringBuilder é uma classe para construção passo a passo de texto estilizado com capacidade de inserir, substituir e excluir fragmentos. Ao contrário do SpannableString, que é criado a partir de uma string pronta e é imutável, o Builder permite adicionar partes de texto sequencialmente e atribuir estilos em tempo real. É ideal para mensagens compostas: logs, chats, manchetes de notícias com rótulos dinâmicos.

O Builder implementa as interfaces Spannable e Editable, tornando-o compatível com EditText. O usuário pode editar o texto, e os estilos são preservados e deslocados corretamente ao inserir novos caracteres. SpannableString, por ser imutável, não é adequado para campos editáveis.

Encadeamento de Métodos

O método append() retorna o próprio builder, permitindo o encadeamento de métodos. Após adicionar texto, os spans são aplicados através de setSpan(). As posições são especificadas em relação ao comprimento atual do builder. Insert() e replace() também estão disponíveis para controle mais preciso do conteúdo.

kotlin
val builder = SpannableStringBuilder()
    .append("New ")
    .append("comment")
val blue = ForegroundColorSpan(Color.BLUE)
val gray = ForegroundColorSpan(Color.GRAY)
builder.setSpan(blue, 0, 6, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
builder.setSpan(gray, 6, 17, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
textView.text = builder

O texto “Novo ” está colorido em azul, e “comentário” em cinza. Ao inserir caracteres adicionais entre eles, o span não afetará o novo texto graças às flags EXCLUSIVE. O Builder ajusta automaticamente os índices internos ao ser modificado.

Desempenho e Otimização de Spans

Usar um grande número de spans afeta o desempenho de renderização do TextView. Cada span chama o método updateDrawState() ou updateMeasureState() em cada redesenho. Recomenda-se limitar a quantidade de spans por TextView a 50–100 para desempenho confortável em dispositivos de médio porte. Spans que alteram o tamanho do texto (RelativeSizeSpan, AbsoluteSizeSpan) exigem recálculo do layout a cada alteração, o que é significativamente mais caro do que spans apenas de cor ou sublinhado.

TextAppearanceSpan

TextAppearanceSpan permite aplicar um conjunto completo de estilos de um recurso XML android:textAppearance com uma única chamada setSpan(). Em vez de três spans separados (cor, tamanho, fonte), um único TextAppearanceSpan com uma referência de estilo é usado. Isso reduz o número de objetos e simplifica a manutenção — alterar o estilo no recurso se aplica automaticamente a todos os textos que usam este span.

Reutilização de Objetos

Criar uma nova instância de span para cada setSpan() adiciona carga extra ao coletor de lixo. É ideal criar objetos span constantes se forem usados repetidamente. Por exemplo, ForegroundColorSpan(Color.RED) pode ser armazenado em um objeto companion e reutilizado. No entanto, spans com estado (ClickableSpan com diferentes manipuladores) devem ser criados individualmente para cada caso.

Medição e Perfilamento

Para diagnosticar problemas de desempenho com spans, use Layout Inspector no Android Studio e o perfilador de GPU. Se um TextView com muitos spans ficar visivelmente lento durante a rolagem, considere substituir alguns spans por estilos estáticos através de TextAppearanceSpan ou reduzir o número de spans combinando atributos em implementações personalizadas de UpdateAppearance.

Perguntas Frequentes

Como o SpannableString difere de uma String comum?

String é uma sequência imutável de caracteres sem suporte a estilos. SpannableString armazena os mesmos caracteres, mas adicionalmente contém um array de objetos Span com informações de formatação. O TextView determina o tipo de CharSequence passado e aplica os spans aos intervalos correspondentes durante a renderização. String ignora quaisquer atributos de estilo e é exibida como texto simples.

Como remover todos os spans de SpannableString?

O método removeSpan(Object span) remove um span específico. Para limpeza completa, chame getSpans(0, length, Object::class.java), que retorna um array de todos os spans, e então remova cada um através de removeSpan. Alternativamente, crie um novo SpannableString(text.toString()) sem spans. SpannableStringBuilder tem um método clear() que remove tanto o texto quanto os spans.

O SpannableString funciona no EditText?

SpannableString funciona no EditText, mas para texto editável é preferível SpannableStringBuilder, que implementa Editable. EditText requer a interface Editable para rastrear alterações. Se você passar SpannableString para EditText, o texto será exibido com estilos, mas durante a edição o Android o converterá para Editable, o que pode redefinir alguns spans.

Pode-se usar SpannableString no Compose?

No Jetpack Compose, os spans do Android SDK não são usados diretamente. Em vez disso, o Compose fornece AnnotatedString, seu próprio equivalente ao SpannableString com capacidades semelhantes: SpanStyle para estilos de caracteres individuais e ParagraphStyle para parágrafos. A conversão de SpannableString para AnnotatedString é possível através de buildAnnotatedString com iteração sobre os spans.

Como criar um Span personalizado?

Crie uma classe que estenda CharacterStyle e sobrescreva o método updateDrawState(TextPaint tp). Dentro do método, modifique as propriedades do TextPaint: cor, espessura do traço, efeitos. Para alterações métricas, use UpdateLayout ou MetricAffectingSpan. Spans personalizados são aplicados através de setSpan() assim como os incorporados.

Resumo

  • SpannableString — uma classe Android para estilizar texto através de objetos Span com vinculação a intervalos de caracteres
  • CharacterStyle afeta caracteres individuais, ParagraphStyle afeta parágrafos inteiros
  • Spans principais: ForegroundColorSpan, StyleSpan, RelativeSizeSpan, URLSpan, ClickableSpan
  • SpannableStringBuilder — uma versão mutável para construção dinâmica de texto com Editable
  • Combinar spans é seguro — cada span altera seu próprio atributo independentemente
  • Flags de Span controlam o comportamento do span ao inserir texto nos limites
  • Otimização: use TextAppearanceSpan para grupos de estilo e limite spans a 100

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.

Discutir o projeto

Leia também