SpannableString: Was es ist, Stilklassen und wie es funktioniert

Autor: IT Sectr Veröffentlicht: 2026-07-23 Lesezeit: 10 Min.

SpannableString ist eine Android-SDK-Klasse aus dem Paket android.text, mit der Sie mehrere Stile auf verschiedene Teile einer einzelnen Textzeichenfolge in TextView anwenden können. Im Gegensatz zu HTML-Markup arbeitet SpannableString auf der Ebene von Span-Objekten und steuert die visuelle Darstellung von Text: Farbe, Größe, Schriftart, Unterstreichung und interaktive Elemente. Laut Google Developers wird SpannableString in Android-Systemkomponenten zum Formatieren von Links verwendet. Es ist die primäre Methode, um Text ohne Drittanbieterbibliotheken zu gestalten.

Wichtige Punkte

  • SpannableString — eine Android-Klasse zum Gestalten von Text über Span-Objekte, nach der Erstellung unveränderlich
  • Spans werden unterteilt in CharacterStyle (einzelne Zeichen) und ParagraphStyle (ganze Absätze)
  • ForegroundColorSpan ändert die Textfarbe, StyleSpan ist für Fett und Kursiv zuständig
  • SpannableStringBuilder — eine veränderbare Version für den dynamischen Textaufbau mit Editable-Unterstützung
  • Span-Flags bestimmen das Verhalten des Spans beim Einfügen oder Löschen von Text an Bereichsgrenzen

Was ist SpannableString?

SpannableString ist eine Android-Klasse, die das Spannable-Interface implementiert und Text zusammen mit einer Reihe von Span-Objekten speichert, die die visuelle Darstellung steuern. Im Gegensatz zu einem normalen String ermöglicht SpannableString das Anhängen von Stilattributen an bestimmte Zeichenbereiche: Textteile rot färben, die Schriftgröße in einer Überschrift vergrößern oder einen klickbaren Link innerhalb eines Absatzes hinzufügen.

Die Klasse befindet sich im Paket android.text und ist seit API Level 1 verfügbar. SpannableString ist unveränderlich — einmal erstellt, ist seine Struktur fixiert, und das Ersetzen von Text erfordert die Erstellung eines neuen Objekts. Für die dynamische Bearbeitung wird SpannableStringBuilder verwendet, der das Einfügen und Löschen von Zeichen ohne Stilverlust unterstützt.

Unterschied zu CharSequence

CharSequence ist die Basisschnittstelle für Textdaten, die von String, StringBuilder und SpannableString implementiert wird. Der Hauptunterschied zwischen SpannableString und String ist die Unterstützung zum Anhängen beliebiger Objekte an eine Teilzeichenfolge. TextView erkennt das Spannable-Interface und wendet während des Renderns Span-Objekte auf die entsprechenden Textsegmente an. Wenn Sie einen normalen String an TextView übergeben, werden keine Stile angewendet.

Interne Struktur

SpannableString speichert Text als char[]-Array und ein separates Array von Span-Objekten mit Metadaten über Start- und Endpositionen. Wenn setSpan(what, start, end, flags) aufgerufen wird, wird das what-Objekt zusammen mit Bereichsinformationen in der Liste gespeichert. Während des Renderns wendet TextView nacheinander alle Spans an, die in den angezeigten Bereich fallen, und ruft die Methoden updateDrawState und updateMeasureState auf.

Span-Typen: CharacterStyle und ParagraphStyle

CharacterStyle ist die Basisklasse für Spans, die einzelne Zeichen unabhängig von ihrer Position in Zeilen beeinflussen. Dazu gehören ForegroundColorSpan (Textfarbe), RelativeSizeSpan (relative Größe), StyleSpan (fett und kursiv), UnderlineSpan (Unterstreichung) und andere. Zeichen-Spans werden auf jedes Zeichen im angegebenen Bereich einzeln angewendet.

ParagraphStyle ist eine Schnittstelle für Spans, die ganze Absätze beeinflussen. Der bekannteste Vertreter ist AlignmentSpan, der den gesamten Absatz links-, mittel- oder rechtsbündig ausrichtet. Absatz-Spans müssen den gesamten Absatz abdecken; andernfalls ignoriert Android ihre Anwendung. Diese Einschränkung besteht, weil Ausrichtung oder Einzug nur für einen ganzen Textblock sinnvoll sind.

Span-Flags

Span-Flags sind vier Konstanten, die das Verhalten des Spans beim Einfügen oder Löschen von Text an den Grenzen seines Bereichs definieren. SPAN_EXCLUSIVE_EXCLUSIVE hält den Span nur innerhalb der ursprünglichen Grenzen aktiv, SPAN_INCLUSIVE_INCLUSIVE erweitert ihn beim Hinzufügen von Text an den Grenzen. SPAN_EXCLUSIVE_INCLUSIVE und SPAN_INCLUSIVE_EXCLUSIVE bieten gemischtes Verhalten für Anfang und Ende des Bereichs.

FlagEinfügen linksEinfügen rechts
SPAN_EXCLUSIVE_EXCLUSIVEschließt nicht einschließt nicht ein
SPAN_INCLUSIVE_INCLUSIVEschließt einschließt ein
SPAN_EXCLUSIVE_INCLUSIVEschließt nicht einschließt ein
SPAN_INCLUSIVE_EXCLUSIVEschließt einschließt nicht ein

Die Wahl des richtigen Flags ist für Editable-Text in EditText entscheidend, wo Benutzer Zeichen einfügen und löschen können. Für schreibgeschütztes TextView wird normalerweise SPAN_EXCLUSIVE_EXCLUSIVE verwendet — der Stil wird nur auf den ursprünglichen Bereich angewendet und erweitert sich nicht bei programmatischen Änderungen.

Wichtige Span-Klassen im Android SDK

Das Android SDK bietet über 25 integrierte Span-Klassen, die die meisten Textgestaltungsaufgaben abdecken. Jede Klasse implementiert das CharacterStyle- oder ParagraphStyle-Interface und akzeptiert Parameter über ihren Konstruktor. Alle Klassen befinden sich im Paket android.text.style und sind ohne zusätzliche Abhängigkeiten verfügbar.

Farb- und Hintergrund-Spans

ForegroundColorSpan setzt die Textfarbe für einen angegebenen Bereich und akzeptiert eine Farbe im int-Format. BackgroundColorSpan färbt den Hintergrund hinter dem Text, nützlich zum Hervorheben von Suchergebnissen. AbsoluteSizeSpan legt eine genaue Schriftgröße in Pixeln fest, RelativeSizeSpan wendet einen Multiplikator relativ zur Basistextgröße in TextView an.

Schriftart-Spans

StyleSpan akzeptiert die Konstanten Typeface.NORMAL, Typeface.BOLD, Typeface.ITALIC oder BOLD_ITALIC und ändert die Schriftart der Zeichen. UnderlineSpan fügt Unterstreichung hinzu, StrikethroughSpan fügt Durchstreichung hinzu. SuperscriptSpan und SubscriptSpan erstellen hoch- und tiefgestellte Zeichen. TypefaceSpan ermöglicht das Festlegen einer benutzerdefinierten Schriftart über ein Typeface-Objekt für einen Textbereich.

Interaktive Spans

ClickableSpan ist eine abstrakte Klasse zum Erstellen klickbarer Textsegmente. Beim Antippen wird die Methode onClick() aufgerufen. Damit Klicks funktionieren, muss TextView setMovementMethod(LinkMovementMethod.getInstance()) haben. URLSpan ist eine Unterklasse von ClickableSpan für Hyperlinks mit automatischem Öffnen des Browsers. ClickableSpan wird oft mit ForegroundColorSpan kombiniert, um den Link visuell blau hervorzuheben.

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

Ohne LinkMovementMethod werden Klicks auf URLSpan nicht verarbeitet. MovementMethod ist für das Abfangen von Berührungsereignissen und das Finden des ClickableSpan an der Berührungsposition verantwortlich. Der Farb-Span macht den Link für den Benutzer sichtbar.

So verwenden Sie SpannableString im Code

Die Arbeit mit SpannableString beginnt mit der Erstellung einer Instanz aus einer Textzeichenfolge und dem sequenziellen Anwenden von Spans über die Methode setSpan(). Die Methode akzeptiert vier Parameter: das Span-Objekt, die Startposition, die Endposition und die Flags. Nach dem Setzen aller Spans wird das Objekt über setText() an TextView übergeben.

Textfarbe und -größe

Erstellen wir eine Zeichenfolge, bei der das erste Wort rot und vergrößert ist. Dazu verwenden wir ForegroundColorSpan für die Farbe und RelativeSizeSpan für den Maßstab. Beide Spans werden unabhängig voneinander auf denselben Bereich angewendet — die Reihenfolge der setSpan-Aufrufe spielt keine Rolle.

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

Zeichen von Position 0 bis 9 erhalten beide Stile gleichzeitig. TextView wendet während des Renderns automatisch alle Spans an — keine zusätzlichen Aufrufe erforderlich. RelativeSizeSpan mit einem Multiplikator von 1,5f erhöht die Schriftgröße um 50% relativ zur Basis.

Kombination mit HTML-Tags

Html.fromHtml() erstellt ein Spanned-Objekt aus einem HTML-String, aber der Satz unterstützter Tags ist begrenzt. SpannableString gibt volle Kontrolle über jedes Attribut ohne HTML-Einschränkungen. Wenn Sie HTML in Spans konvertieren und dann benutzerdefinierte Stile hinzufügen müssen, können Sie Html.fromHtml() als Basis verwenden und dann über setSpan() mit Spans ergänzen.

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

Das Ergebnis — der Text „Wichtig:“ wird fett (aus HTML) und rot (aus dem Span) sein. Dieser Ansatz ist praktisch bei der Arbeit mit Serverinhalten, bei denen ein Teil der Formatierung in HTML angegeben und ein Teil clientseitig programmatisch hinzugefügt wird.

Kombinieren mehrerer Spans

SpannableString ermöglicht das Anwenden einer unbegrenzten Anzahl von Spans auf denselben oder überlappenden Bereich. Das Kombinieren von Spans ist ein entscheidender Vorteil gegenüber HTML-Markup, wo verschachtelte Tags in Konflikt geraten können. Spans sind unabhängig und werden während des Renderns sequenziell angewendet.

Sie können beispielsweise ein Textsegment gleichzeitig fett, rot und klickbar machen. Erstellen Sie dazu drei Spans — StyleSpan, ForegroundColorSpan und ClickableSpan — und wenden Sie jeden auf denselben Bereich an. Die Reihenfolge der Anwendung hat keinen Einfluss auf das Ergebnis, da jeder Span für sein eigenes Textattribut verantwortlich ist.

Überlappung von Spans verschiedener Typen

Wenn sich Spans verschiedener Typen teilweise überlappen, arbeitet jeder unabhängig innerhalb seiner eigenen Grenzen. ForegroundColorSpan im Bereich 0–10 und StyleSpan(BOLD) im Bereich 5–15 ergeben fetten roten Text im Segment 5–10 und nur fett in 10–15. Es treten keine Konflikte auf, da jeder Span während des Renderns sein eigenes Attribut ändert.

Abrufen der Span-Liste

Die Methode getSpans(int start, int end, Class type) gibt ein Array von Spans innerhalb des angegebenen Bereichs zurück. Dies ist nützlich, um zu überprüfen, welche Stile bereits angewendet wurden, oder um bestimmte Spans zu entfernen. Mit nextSpanTransition() können Sie über Span-Änderungsgrenzen iterieren — dies ist die Grundlage für benutzerdefinierte TextView-Implementierungen, die wissen müssen, wo sich der Stil ändert.

SpannableStringBuilder zum Textaufbau

SpannableStringBuilder ist eine Klasse für den schrittweisen Aufbau von formatiertem Text mit der Möglichkeit, Fragmente einzufügen, zu ersetzen und zu löschen. Im Gegensatz zu SpannableString, das aus einem fertigen String erstellt wird und unveränderlich ist, ermöglicht Builder das sequenzielle Hinzufügen von Textteilen und die Zuweisung von Stilen im laufenden Betrieb. Dies ist ideal für zusammengesetzte Nachrichten: Logs, Chats, Nachrichtenüberschriften mit dynamischen Labels.

Builder implementiert die Spannable- und Editable-Schnittstellen, was ihn mit EditText kompatibel macht. Der Benutzer kann den Text bearbeiten, und die Stile bleiben erhalten und werden beim Einfügen neuer Zeichen korrekt verschoben. SpannableString ist als unveränderliches Objekt nicht für bearbeitbare Felder geeignet.

Methodenverkettung

Die Methode append() gibt den Builder selbst zurück, was Methodenverkettung ermöglicht. Nach dem Hinzufügen von Text werden Spans über setSpan() angewendet. Positionen werden relativ zur aktuellen Builder-Länge angegeben. Insert() und replace() stehen für eine präzisere Inhaltskontrolle zur Verfügung.

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

Der Text „Neu “ ist blau gefärbt und „Kommentar“ grau. Beim Einfügen zusätzlicher Zeichen dazwischen wird der Span dank der EXCLUSIVE-Flags den neuen Text nicht beeinflussen. Builder passt die internen Indizes bei Änderungen automatisch an.

Span-Leistung und Optimierung

Die Verwendung vieler Spans beeinträchtigt die Rendering-Leistung von TextView. Jeder Span ruft bei jeder Neuzeichnung die Methode updateDrawState() oder updateMeasureState() auf. Es wird empfohlen, die Anzahl der Spans pro TextView auf 50–100 zu begrenzen, um eine komfortable Leistung auf Mittelklassegeräten zu gewährleisten. Spans, die die Textgröße ändern (RelativeSizeSpan, AbsoluteSizeSpan), erfordern bei jeder Änderung eine Neuberechnung des Layouts, was deutlich teurer ist als reine Farb- oder Unterstreichungs-Spans.

TextAppearanceSpan

TextAppearanceSpan ermöglicht das Anwenden eines ganzen Satzes von Stilen aus einer android:textAppearance-XML-Ressource mit einem einzigen setSpan()-Aufruf. Anstelle von drei separaten Spans (Farbe, Größe, Schriftart) wird ein einzelner TextAppearanceSpan mit einer Stilreferenz verwendet. Dies reduziert die Anzahl der Objekte und vereinfacht die Wartung — eine Änderung des Stils in der Ressource wird automatisch auf alle Texte angewendet, die diesen Span verwenden.

Objektd wiederverwendung

Das Erstellen einer neuen Span-Instanz für jeden setSpan()-Aufruf belastet den Garbage Collector zusätzlich. Optimal ist es, konstante Span-Objekte zu erstellen, wenn sie wiederholt verwendet werden. Beispielsweise kann ForegroundColorSpan(Color.RED) in einem Companion-Objekt gespeichert und wiederverwendet werden. Spans mit Zustand (ClickableSpan mit verschiedenen Handlern) müssen jedoch für jeden Fall einzeln erstellt werden.

Messung und Profiling

Zur Diagnose von Span-Leistungsproblemen verwenden Sie Layout Inspector in Android Studio und den GPU-Profiler. Wenn ein TextView mit vielen Spans beim Scrollen merklich langsamer wird, sollten Sie erwägen, einige Spans durch statische Stile über TextAppearanceSpan zu ersetzen oder die Anzahl der Spans durch Kombinieren von Attributen in benutzerdefinierten UpdateAppearance-Implementierungen zu reduzieren.

Häufig gestellte Fragen

Wie unterscheidet sich SpannableString von einem normalen String?

String ist eine unveränderliche Zeichenfolge ohne Stilunterstützung. SpannableString speichert dieselben Zeichen, enthält aber zusätzlich ein Array von Span-Objekten mit Formatierungsinformationen. TextView bestimmt den Typ des übergebenen CharSequence und wendet die Spans während des Renderns auf die entsprechenden Bereiche an. String ignoriert alle Stilattribute und wird als Klartext angezeigt.

Wie entferne ich alle Spans aus SpannableString?

Die Methode removeSpan(Object span) entfernt einen bestimmten Span. Für eine vollständige Bereinigung rufen Sie getSpans(0, length, Object::class.java) auf, das ein Array aller Spans zurückgibt, und entfernen Sie dann jeden über removeSpan. Alternativ erstellen Sie einen neuen SpannableString(text.toString()) ohne Spans. SpannableStringBuilder hat eine clear()-Methode, die sowohl Text als auch Spans entfernt.

Funktioniert SpannableString in EditText?

SpannableString funktioniert in EditText, aber für bearbeitbaren Text ist SpannableStringBuilder vorzuziehen, der Editable implementiert. EditText benötigt das Editable-Interface, um Änderungen zu verfolgen. Wenn Sie SpannableString an EditText übergeben, wird der Text mit Stilen angezeigt, aber während der Bearbeitung konvertiert Android ihn in Editable, was einige Spans zurücksetzen kann.

Kann SpannableString in Compose verwendet werden?

In Jetpack Compose werden Android-SDK-Spans nicht direkt verwendet. Stattdessen bietet Compose AnnotatedString an, sein eigenes Äquivalent zu SpannableString mit ähnlichen Fähigkeiten: SpanStyle für einzelne Zeichenstile und ParagraphStyle für Absätze. Die Konvertierung von SpannableString in AnnotatedString ist über buildAnnotatedString mit Iteration über Spans möglich.

Wie erstelle ich einen benutzerdefinierten Span?

Erstellen Sie eine Klasse, die CharacterStyle erweitert, und überschreiben Sie die Methode updateDrawState(TextPaint tp). Innerhalb der Methode ändern Sie die TextPaint-Eigenschaften: Farbe, Strichstärke, Effekte. Für metrische Änderungen verwenden Sie UpdateLayout oder MetricAffectingSpan. Benutzerdefinierte Spans werden genau wie integrierte Spans über setSpan() angewendet.

Zusammenfassung

  • SpannableString — eine Android-Klasse zum Gestalten von Text über Span-Objekte mit Zeichenbereichsbindung
  • CharacterStyle beeinflusst einzelne Zeichen, ParagraphStyle beeinflusst ganze Absätze
  • Wichtige Spans: ForegroundColorSpan, StyleSpan, RelativeSizeSpan, URLSpan, ClickableSpan
  • SpannableStringBuilder — eine veränderbare Version für dynamischen Textaufbau mit Editable
  • Spans kombinieren ist sicher — jeder Span ändert unabhängig sein eigenes Attribut
  • Span-Flags steuern das Span-Verhalten beim Einfügen von Text an Grenzen
  • Optimierung: Verwenden Sie TextAppearanceSpan für Stilgruppen und begrenzen Sie Spans auf 100

Wir entwickeln eine mobile Applikation schlüsselfertig

IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.

Projekt besprechen

Lesen Sie auch