SpannableString: cos'è, classi di stile e come funziona

Autore: IT Sectr Pubblicato: 2026-07-23 Tempo di lettura: 10 min

SpannableString è una classe Android SDK del pacchetto android.text che consente di applicare più stili a diverse parti di una singola stringa di testo in TextView. A differenza del markup HTML, SpannableString lavora a livello di oggetti Span, controllando la visualizzazione del testo: colore, dimensione, carattere, sottolineatura ed elementi interattivi. Secondo Google Developers, SpannableString viene utilizzato nei componenti di sistema Android per formattare i collegamenti. È il modo principale per stilizzare il testo senza usare librerie di terze parti.

Punti Chiave

  • SpannableString — una classe Android per stilizzare il testo tramite oggetti Span, immutabile dopo la creazione
  • Gli span si dividono in CharacterStyle (caratteri individuali) e ParagraphStyle (paragrafi interi)
  • ForegroundColorSpan cambia il colore del testo, StyleSpan gestisce grassetto e corsivo
  • SpannableStringBuilder — una versione mutabile per la costruzione dinamica del testo con supporto Editable
  • I flag Span determinano il comportamento dello span durante l'inserimento o la cancellazione del testo ai confini dell'intervallo

Cos'è SpannableString?

SpannableString è una classe Android che implementa l'interfaccia Spannable, memorizzando il testo insieme a un insieme di oggetti Span che controllano la visualizzazione. A differenza di una String normale, SpannableString consente di allegare attributi di stile a intervalli specifici di caratteri: rendere rossa una parte del testo, aumentare la dimensione del carattere in un'intestazione o aggiungere un link cliccabile all'interno di un paragrafo.

La classe si trova nel pacchetto android.text ed è disponibile dall'API Level 1. SpannableString è immutabile — una volta creata, la sua struttura è fissa e la sostituzione del testo richiede la creazione di un nuovo oggetto. Per la modifica dinamica si usa SpannableStringBuilder, che supporta l'inserimento e la cancellazione di caratteri senza perdere gli stili.

Differenza da CharSequence

CharSequence è l'interfaccia di base per i dati testuali, implementata da String, StringBuilder e SpannableString. La differenza principale tra SpannableString e String è il supporto per allegare oggetti arbitrari a una sottostringa. TextView riconosce l'interfaccia Spannable e applica gli oggetti span ai segmenti di testo corrispondenti durante il rendering. Se passi una String normale a TextView, nessuno stile verrà applicato.

Struttura Interna

SpannableString memorizza il testo come array char[] e un array separato di oggetti span con metadati sulle posizioni di inizio e fine. Quando viene chiamato setSpan(what, start, end, flags), l'oggetto what viene salvato nell'elenco insieme alle informazioni sull'intervallo. Durante il rendering, TextView applica sequenzialmente tutti gli span che rientrano nell'intervallo visualizzato, chiamando i metodi updateDrawState e updateMeasureState.

Tipi di Span: CharacterStyle e ParagraphStyle

CharacterStyle è la classe base per gli span che influenzano caratteri individuali indipendentemente dalla loro posizione nelle righe. Questo include ForegroundColorSpan (colore del testo), RelativeSizeSpan (dimensione relativa), StyleSpan (grassetto e corsivo), UnderlineSpan (sottolineatura) e altri. Gli span di carattere vengono applicati a ciascun carattere nell'intervallo specificato individualmente.

ParagraphStyle è un'interfaccia per gli span che influenzano paragrafi interi. Il rappresentante più noto è AlignmentSpan, che allinea l'intero paragrafo a sinistra, centro o destra. Gli span di paragrafo devono coprire l'intero paragrafo; altrimenti, Android ignora la loro applicazione. Questa limitazione è dovuta al fatto che l'allineamento o il rientro hanno senso solo per un blocco di testo completo.

Flag di Span

I flag di Span sono quattro costanti che definiscono il comportamento dello span quando il testo viene inserito o cancellato ai confini del suo intervallo. SPAN_EXCLUSIVE_EXCLUSIVE mantiene lo span attivo solo all'interno dei confini originali, SPAN_INCLUSIVE_INCLUSIVE lo estende quando il testo viene aggiunto ai confini. SPAN_EXCLUSIVE_INCLUSIVE e SPAN_INCLUSIVE_EXCLUSIVE forniscono un comportamento misto per l'inizio e la fine dell'intervallo.

FlagInserimento a SinistraInserimento a Destra
SPAN_EXCLUSIVE_EXCLUSIVEnon includenon include
SPAN_INCLUSIVE_INCLUSIVEincludeinclude
SPAN_EXCLUSIVE_INCLUSIVEnon includeinclude
SPAN_INCLUSIVE_EXCLUSIVEincludenon include

Scegliere il flag corretto è fondamentale per il testo Editable in EditText, dove l'utente può inserire e cancellare caratteri. Per TextView di sola lettura, si usa tipicamente SPAN_EXCLUSIVE_EXCLUSIVE — lo stile si applica solo all'intervallo originale e non si espande con modifiche programmatiche.

Principali Classi di Span in Android SDK

L'SDK Android fornisce oltre 25 classi di span integrate che coprono la maggior parte delle attività di stilizzazione del testo. Ogni classe implementa l'interfaccia CharacterStyle o ParagraphStyle e accetta parametri tramite il suo costruttore. Tutte le classi si trovano nel pacchetto android.text.style e sono disponibili senza aggiungere dipendenze extra.

Span di Colore e Sfondo

ForegroundColorSpan imposta il colore del testo per un intervallo specificato, accettando un colore in formato int. BackgroundColorSpan colora lo sfondo dietro il testo, utile per evidenziare i risultati di ricerca. AbsoluteSizeSpan imposta una dimensione esatta del carattere in pixel, RelativeSizeSpan applica un moltiplicatore relativo alla dimensione base del testo in TextView.

Span di Carattere

StyleSpan accetta le costanti Typeface.NORMAL, Typeface.BOLD, Typeface.ITALIC o BOLD_ITALIC e modifica il carattere dei simboli. UnderlineSpan aggiunge la sottolineatura, StrikethroughSpan aggiunge la barratura. SuperscriptSpan e SubscriptSpan creano apice e pedice. TypefaceSpan consente di impostare un carattere personalizzato tramite un oggetto Typeface per un intervallo di testo.

Span Interattivi

ClickableSpan è una classe astratta per creare segmenti di testo cliccabili. Al tocco, viene chiamato il metodo onClick(). Affinché i clic funzionino, TextView deve avere setMovementMethod(LinkMovementMethod.getInstance()). URLSpan è una sottoclasse di ClickableSpan per i collegamenti ipertestuali con apertura automatica del browser. ClickableSpan è spesso combinato con ForegroundColorSpan per evidenziare visivamente il collegamento in blu.

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()

Senza LinkMovementMethod, i clic su URLSpan non verranno elaborati. MovementMethod è responsabile dell'intercettazione degli eventi tattili e della ricerca del ClickableSpan nella posizione del tocco. Lo span di colore rende il collegamento visibile all'utente.

Come Usare SpannableString nel Codice

Lavorare con SpannableString inizia creando un'istanza da una stringa di testo e applicando sequenzialmente gli span tramite il metodo setSpan(). Il metodo accetta quattro parametri: l'oggetto span, la posizione iniziale, la posizione finale e i flag. Dopo aver impostato tutti gli span, l'oggetto viene passato a TextView tramite setText().

Colore e Dimensione del Testo

Creiamo una stringa in cui la prima parola sia rossa e ingrandita. Per questo, usiamo ForegroundColorSpan per il colore e RelativeSizeSpan per la scala. Entrambi gli span vengono applicati allo stesso intervallo in modo indipendente — l'ordine delle chiamate setSpan non ha importanza.

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

I caratteri dalla posizione 0 alla 9 ricevono entrambi gli stili simultaneamente. TextView applica automaticamente tutti gli span durante il rendering — non sono necessarie chiamate aggiuntive. RelativeSizeSpan con un moltiplicatore di 1.5f aumenta la dimensione del carattere del 50% rispetto alla base.

Combinazione con Tag HTML

Html.fromHtml() crea un oggetto Spanned da una stringa HTML, ma l'insieme di tag supportati è limitato. SpannableString dà il controllo completo su ogni attributo senza le limitazioni dell'HTML. Se è necessario convertire HTML in span e poi aggiungere stili personalizzati, puoi usare Html.fromHtml() come base e poi integrare con span tramite 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

Il risultato — il testo “Importante:” sarà in grassetto (dall'HTML) e rosso (dallo span). Questo approccio è comodo quando si lavora con contenuti server dove parte della formattazione è specificata in HTML e parte viene aggiunta lato client programmaticamente.

Combinazione di Più Span

SpannableString consente di applicare un numero illimitato di span allo stesso intervallo o a intervalli sovrapposti. Combinare gli span è un vantaggio chiave rispetto al markup HTML, dove i tag annidati possono entrare in conflitto. Gli span sono indipendenti e vengono applicati sequenzialmente durante il rendering.

Ad esempio, puoi rendere un segmento di testo simultaneamente grassetto, rosso e cliccabile. Per farlo, crea tre span — StyleSpan, ForegroundColorSpan e ClickableSpan — e applica ciascuno allo stesso intervallo. L'ordine di applicazione non influisce sul risultato, poiché ogni span è responsabile del proprio attributo di testo.

Sovrapposizione di Span di Diversi Tipi

Se span di diversi tipi si sovrappongono parzialmente, ciascuno funziona indipendentemente all'interno dei propri confini. ForegroundColorSpan sull'intervallo 0–10 e StyleSpan(BOLD) sull'intervallo 5–15 daranno testo rosso grassetto sul segmento 5–10 e solo grassetto su 10–15. Non sorgono conflitti perché ogni span modifica il proprio attributo durante il rendering.

Ottenere l'Elenco degli Span

Il metodo getSpans(int start, int end, Class type) restituisce un array di span all'interno dell'intervallo specificato. Questo è utile per verificare quali stili sono già applicati o per rimuovere span specifici. Con nextSpanTransition(), puoi iterare sui confini di cambiamento degli span — questa è la base per implementazioni personalizzate di TextView che devono sapere dove lo stile cambia.

SpannableStringBuilder per la Costruzione del Testo

SpannableStringBuilder è una classe per la costruzione passo-passo di testo stilizzato con la possibilità di inserire, sostituire ed eliminare frammenti. A differenza di SpannableString, che viene creato da una stringa pronta ed è immutabile, Builder consente di aggiungere parti di testo sequenzialmente e assegnare stili al volo. È ideale per messaggi compositi: log, chat, titoli di notizie con etichette dinamiche.

Builder implementa le interfacce Spannable e Editable, rendendolo compatibile con EditText. L'utente può modificare il testo e gli stili vengono preservati e spostati correttamente quando vengono inseriti nuovi caratteri. SpannableString, essendo immutabile, non è adatto per campi modificabili.

Concatenamento di Metodi

Il metodo append() restituisce il builder stesso, consentendo il concatenamento dei metodi. Dopo aver aggiunto il testo, gli span vengono applicati tramite setSpan(). Le posizioni sono specificate rispetto alla lunghezza corrente del builder. Insert() e replace() sono anche disponibili per un controllo più preciso del contenuto.

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

Il testo “Nuovo ” è colorato in blu e “commento” in grigio. Inserendo caratteri aggiuntivi tra di loro, lo span non influenzerà il nuovo testo grazie ai flag EXCLUSIVE. Builder regola automaticamente gli indici interni durante la modifica.

Prestazioni e Ottimizzazione degli Span

L'uso di un gran numero di span influisce sulle prestazioni di rendering di TextView. Ogni span chiama il metodo updateDrawState() o updateMeasureState() a ogni ridisegno. Si consiglia di limitare il numero di span per TextView a 50–100 per prestazioni confortevoli su dispositivi di fascia media. Gli span che modificano la dimensione del testo (RelativeSizeSpan, AbsoluteSizeSpan) richiedono il ricalcolo del layout a ogni modifica, il che è significativamente più costoso degli span solo colore o sottolineatura.

TextAppearanceSpan

TextAppearanceSpan consente di applicare un intero set di stili da una risorsa XML android:textAppearance con una singola chiamata setSpan(). Invece di tre span separati (colore, dimensione, carattere), viene usato un singolo TextAppearanceSpan con un riferimento allo stile. Questo riduce il numero di oggetti e semplifica la manutenzione — la modifica dello stile nella risorsa si applica automaticamente a tutti i testi che usano questo span.

Riutilizzo degli Oggetti

Creare una nuova istanza di span per ogni setSpan() aggiunge carico extra al garbage collector. È ottimale creare oggetti span costanti se vengono usati ripetutamente. Ad esempio, ForegroundColorSpan(Color.RED) può essere memorizzato in un oggetto companion e riutilizzato. Tuttavia, gli span con stato (ClickableSpan con diversi gestori) devono essere creati individualmente per ogni caso.

Misurazione e Profilazione

Per diagnosticare problemi di prestazioni degli span, usa Layout Inspector in Android Studio e il profiler GPU. Se una TextView con molti span rallenta notevolmente durante lo scorrimento, considera di sostituire alcuni span con stili statici tramite TextAppearanceSpan o di ridurre il numero di span combinando attributi in implementazioni personalizzate di UpdateAppearance.

Domande Frequenti

In cosa si differenzia SpannableString da una String normale?

String è una sequenza immutabile di caratteri senza supporto per gli stili. SpannableString memorizza gli stessi caratteri ma contiene inoltre un array di oggetti Span con informazioni di formattazione. TextView determina il tipo di CharSequence passato e applica gli span agli intervalli corrispondenti durante il rendering. String ignora qualsiasi attributo di stile e viene visualizzato come testo semplice.

Come rimuovere tutti gli span da SpannableString?

Il metodo removeSpan(Object span) rimuove uno span specifico. Per una pulizia completa, chiama getSpans(0, length, Object::class.java), che restituisce un array di tutti gli span, e poi rimuovi ciascuno tramite removeSpan. In alternativa, crea un nuovo SpannableString(text.toString()) senza span. SpannableStringBuilder ha un metodo clear() che rimuove sia il testo che gli span.

SpannableString funziona in EditText?

SpannableString funziona in EditText, ma per testo modificabile è preferibile SpannableStringBuilder, che implementa Editable. EditText richiede l'interfaccia Editable per tracciare le modifiche. Se passi SpannableString a EditText, il testo verrà visualizzato con gli stili, ma durante la modifica Android lo convertirà in Editable, il che potrebbe reimpostare alcuni span.

Si può usare SpannableString in Compose?

In Jetpack Compose, gli span di Android SDK non vengono usati direttamente. Invece, Compose fornisce AnnotatedString, il suo equivalente di SpannableString con capacità simili: SpanStyle per gli stili di caratteri individuali e ParagraphStyle per i paragrafi. La conversione da SpannableString ad AnnotatedString è possibile tramite buildAnnotatedString con iterazione sugli span.

Come creare uno Span personalizzato?

Crea una classe che estende CharacterStyle e sovrascrivi il metodo updateDrawState(TextPaint tp). All'interno del metodo, modifica le proprietà di TextPaint: colore, spessore del tratto, effetti. Per modifiche metriche, usa UpdateLayout o MetricAffectingSpan. Gli span personalizzati vengono applicati tramite setSpan() proprio come quelli integrati.

Riepilogo

  • SpannableString — una classe Android per stilizzare il testo tramite oggetti Span con associazione a intervalli di caratteri
  • CharacterStyle influisce sui caratteri individuali, ParagraphStyle influisce sui paragrafi interi
  • Span principali: ForegroundColorSpan, StyleSpan, RelativeSizeSpan, URLSpan, ClickableSpan
  • SpannableStringBuilder — una versione mutabile per la costruzione dinamica del testo con Editable
  • Combinare gli span è sicuro — ogni span modifica il proprio attributo indipendentemente
  • I flag Span controllano il comportamento dello span all'inserimento del testo ai confini
  • Ottimizzazione: usa TextAppearanceSpan per gruppi di stile e limita gli span a 100

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche