Spans

Schreiben Sie jetzt
Jetpack Compose ist das empfohlene UI-Toolkit für Android. Hier erfahren Sie, wie Sie Text in „Schreiben“ verwenden.
<ph type="x-smartling-placeholder"></ph> Verschiedene Stile für Text →

Spans sind leistungsstarke Markup-Objekte, mit denen Sie Text an der Zeichen- oder Absatzebene enthalten. Durch das Anhängen von Spans an Textobjekte können Sie Text hinzufügen, z. B. durch Hinzufügen von Farbe, Skalieren der Textgröße und benutzerdefiniertes Zeichnen von Text. Spans können auch TextPaint-Eigenschaften ändern, auf einem Canvas und ändern Sie das Textlayout.

Android bietet mehrere Arten von Spans, die eine Vielzahl von gängigen Texten abdecken. und Stilmustern. Sie können auch eigene Spans erstellen, um benutzerdefinierte Stile anzuwenden.

.

Span erstellen und anwenden

Zum Erstellen von Spans können Sie eine der in der folgenden Tabelle aufgeführten Klassen verwenden. Die Klassen unterscheiden sich je nachdem, ob der Text selbst änderbar ist, das Markup änderbar ist und welche zugrunde liegende Datenstruktur die Span-Daten enthält.

Klasse Veränderlicher Text Veränderliches Markup Datenstruktur
SpannedString Nein Nein Lineares Array
SpannableString Nein Ja Lineares Array
SpannableStringBuilder Ja Ja Intervallstruktur

Alle drei Klassen erweitern die Spanned . SpannableString und SpannableStringBuilder erweitern außerdem die Spannable-Oberfläche.

So entscheiden Sie, welche Version Sie verwenden möchten:

  • Falls Sie den Text oder das Markup nach der Erstellung nicht ändern, verwenden Sie SpannedString
  • Wenn Sie eine kleine Anzahl von Spans an ein einzelnes Textobjekt der Text selbst schreibgeschützt ist, verwenden Sie SpannableString.
  • Wenn Sie Text nach der Erstellung ändern und Spans an den Text, verwenden Sie SpannableStringBuilder.
  • Wenn Sie eine große Anzahl von Spans an ein Textobjekt anhängen müssen, ob der Text schreibgeschützt ist, verwende SpannableStringBuilder.

Rufen Sie setSpan(Object _what_, int _start_, int _end_, int _flags_) auf, um einen Span anzuwenden. für ein Spannable-Objekt. Der Parameter what bezieht sich auf die entsprechende Spanne. auf den Text angewendet und die Parameter start und end geben den Teil an, des Textes, auf den Sie die Spanne anwenden.

Wenn Sie Text innerhalb der Grenzen eines Spans einfügen, wird dieser automatisch zu den eingefügten Text enthält. Wenn Sie Text an der Spanne einfügen Grenzen, d. h. am start- oder end-Index, den Flags legt fest, ob die Spanne so erweitert wird, dass sie den eingefügten Text enthält. Verwenden Sie die Spannable.SPAN_EXCLUSIVE_INCLUSIVE Flag, um eingefügten Text einzuschließen, und verwenden Sie Spannable.SPAN_EXCLUSIVE_EXCLUSIVE um den eingefügten Text auszuschließen.

Das folgende Beispiel zeigt, wie ein ForegroundColorSpan in ein String:

Kotlin

val spannable = SpannableStringBuilder("Text is spantastic!")
spannable.setSpan(
    ForegroundColorSpan(Color.RED),
    8, // start
    12, // end
    Spannable.SPAN_EXCLUSIVE_INCLUSIVE
)

Java

SpannableStringBuilder spannable = new SpannableStringBuilder("Text is spantastic!");
spannable.setSpan(
    new ForegroundColorSpan(Color.RED),
    8, // start
    12, // end
    Spannable.SPAN_EXCLUSIVE_INCLUSIVE
);
<ph type="x-smartling-placeholder">
</ph> Ein Bild mit grauem Text, teilweise rot. <ph type="x-smartling-placeholder">
</ph> Abbildung 1: Text mit einem ForegroundColorSpan

Da der Span mit Spannable.SPAN_EXCLUSIVE_INCLUSIVE festgelegt wird, gilt der Span wird erweitert, sodass an den Span-Grenzen eingefügter Text enthalten ist, wie in den folgendes Beispiel:

Kotlin

val spannable = SpannableStringBuilder("Text is spantastic!")
spannable.setSpan(
    ForegroundColorSpan(Color.RED),
    8, // start
    12, // end
    Spannable.SPAN_EXCLUSIVE_INCLUSIVE
)
spannable.insert(12, "(& fon)")

Java

SpannableStringBuilder spannable = new SpannableStringBuilder("Text is spantastic!");
spannable.setSpan(
    new ForegroundColorSpan(Color.RED),
    8, // start
    12, // end
    Spannable.SPAN_EXCLUSIVE_INCLUSIVE
);
spannable.insert(12, "(& fon)");
<ph type="x-smartling-placeholder">
</ph> Ein Bild, das zeigt, wie der Span bei Verwendung von SPAN_EXCLUSIVE_INCLUSIVE mehr Text enthält. <ph type="x-smartling-placeholder">
</ph> Abbildung 2: Der Span wird erweitert, sodass er zusätzlichen Text bei Verwendung von Spannable.SPAN_EXCLUSIVE_INCLUSIVE

Sie können mehrere Spans an denselben Text anhängen. Das folgende Beispiel zeigt, um Text fett und rot zu erstellen:

Kotlin

val spannable = SpannableString("Text is spantastic!")
spannable.setSpan(ForegroundColorSpan(Color.RED), 8, 12, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
spannable.setSpan(
    StyleSpan(Typeface.BOLD),
    8,
    spannable.length,
    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)

Java

SpannableString spannable = new SpannableString("Text is spantastic!");
spannable.setSpan(
    new ForegroundColorSpan(Color.RED),
    8, 12,
    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
);
spannable.setSpan(
    new StyleSpan(Typeface.BOLD),
    8, spannable.length(),
    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
);
<ph type="x-smartling-placeholder">
</ph> Ein Bild, das einen Text mit mehreren Spans zeigt: „ForegroundColorSpan(Color.RED)“ und „StyleSpan(BOLD)“ <ph type="x-smartling-placeholder">
</ph> Abbildung 3: Text mit mehreren Spannen: ForegroundColorSpan(Color.RED) und StyleSpan(BOLD).

Android-Span-Typen

Android bietet mehr als 20 Span-Typen im android.text.style-Paket. Android kategorisiert Spans hauptsächlich auf zwei Arten:

  • Auswirkung der Spanne auf den Text: Eine Spanne kann die Darstellung oder den Text von Text beeinflussen Messwerte.
  • Span-Bereich: Einige Spans können auf einzelne Zeichen angewendet werden, während andere auf einen ganzen Absatz angewendet werden.
<ph type="x-smartling-placeholder">
</ph> Ein Bild, auf dem verschiedene Span-Kategorien zu sehen sind <ph type="x-smartling-placeholder">
</ph> Abbildung 4: Kategorien von Android-Spans

In den folgenden Abschnitten werden diese Kategorien ausführlicher beschrieben.

Spans, die sich auf die Textdarstellung auswirken

Einige Spans auf Zeichenebene wirken sich auf die Textdarstellung aus, z. B. Text- oder Hintergrundfarbe ändern und Unter- und Unterstreichungen hinzufügen Diese Spans erweitern den Klasse CharacterStyle.

Das folgende Codebeispiel zeigt, wie Sie mit UnderlineSpan unterstreichen. Text:

Kotlin

val string = SpannableString("Text with underline span")
string.setSpan(UnderlineSpan(), 10, 19, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)

Java

SpannableString string = new SpannableString("Text with underline span");
string.setSpan(new UnderlineSpan(), 10, 19, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
<ph type="x-smartling-placeholder">
</ph> Ein Bild, auf dem zu sehen ist, wie Text mit einem „UnderlineSpan“ unterstrichen wird <ph type="x-smartling-placeholder">
</ph> Abbildung 5: Text unterstrichen mit einem UnderlineSpan

Spans, die nur die Textdarstellung betreffen, lösen eine Neuzeichnung des Textes ohne das eine Neuberechnung des Layouts auslöst. Diese Spans implementieren UpdateAppearance und erweitern CharacterStyle Abgeleitete CharacterStyle-Klassen definieren, wie Text gezeichnet wird, indem sie Zugriff auf TextPaint aktualisieren.

Spans, die sich auf Textmesswerte auswirken

Andere Spannen auf Zeichenebene wirken sich auf Textmesswerte aus, z. B. und Textgröße. Diese Spannen erweitern die MetricAffectingSpan .

Mit dem folgenden Codebeispiel wird ein RelativeSizeSpan, die erhöht die Textgröße um 50%:

Kotlin

val string = SpannableString("Text with relative size span")
string.setSpan(RelativeSizeSpan(1.5f), 10, 24, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)

Java

SpannableString string = new SpannableString("Text with relative size span");
string.setSpan(new RelativeSizeSpan(1.5f), 10, 24, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
<ph type="x-smartling-placeholder">
</ph> Ein Bild, das die Verwendung von RelativeSizeSpan zeigt <ph type="x-smartling-placeholder">
</ph> Abbildung 6: Text vergrößert mit einem RelativeSizeSpan

Die Anwendung eines Spans, der sich auf Textmesswerte auswirkt, führt dazu, dass ein beobachtendes Objekt Messen Sie den Text erneut, um ein korrektes Layout und Rendering zu gewährleisten. Ändern Sie beispielsweise kann es vorkommen, dass Wörter in verschiedenen Zeilen stehen. Anwenden der vorstehenden span löst eine erneute Messung, Neuberechnung des Textlayouts und im Text.

Spans, die sich auf Textmesswerte auswirken, erweitern die MetricAffectingSpan-Klasse, eine Abstrakte Klasse, mit der abgeleitete Klassen definieren können, wie sich der Span auf die Textmessung auswirkt durch Zugriff auf die TextPaint. Da MetricAffectingSpan CharacterSpan beeinflussen die abgeleiteten Klassen die Darstellung des Textes am Zeichen.

Spans, die sich auf Absätze auswirken

Eine Spanne kann sich auch auf den Text auf Absatzebene auswirken, z. B. durch Ändern der oder den Rand eines Textblocks. Spans, die ganze Absätze betreffen ParagraphStyle implementieren. Bis diese Spans verwenden, werden sie an den gesamten Absatz angehängt, ohne das Ende Zeilenumbruchzeichen. Wenn Sie versuchen, eine Absatzspanne auf etwas anderes als einen ganzen Absatz beginnen, wendet Android diese Spanne überhaupt nicht an.

Abbildung 8 zeigt, wie Android Absätze im Text trennt.

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph> Abbildung 7: In Android enden Absätze mit einem Zeilenvorschubzeichen (\n).

Im folgenden Codebeispiel wird ein QuoteSpan zu einem Absatz hinzufügen. Beachten Sie, dass wenn Sie die Span an einer anderen Position als am Anfang oder Ende eines wird der Stil bei Android überhaupt nicht angewendet.

Kotlin

spannable.setSpan(QuoteSpan(color), 8, text.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)

Java

spannable.setSpan(new QuoteSpan(color), 8, text.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
<ph type="x-smartling-placeholder">
</ph> Bild, das ein Beispiel für QuoteSpan zeigt <ph type="x-smartling-placeholder">
</ph> Abbildung 8: Ein QuoteSpan auf einen Absatz angewendet.

Benutzerdefinierte Spans erstellen

Wenn Sie mehr Funktionen benötigen, als in der bisherigen Android-Version können Sie benutzerdefinierte Spans implementieren. Entscheiden Sie beim Implementieren eines eigenen Spans ob sich die Spanne auf den Text auf Zeichen- oder Absatzebene auswirkt und und ob sie sich auf das Layout oder das Erscheinungsbild des Textes auswirken. Dies hilft Ihnen, Bestimmen, welche Basisklassen erweitert werden können und welche Schnittstellen Sie möglicherweise benötigen zu implementieren. Die folgende Tabelle dient als Referenz:

Szenario Klasse oder Benutzeroberfläche
Die Spanne wirkt sich auf den Text auf Zeichenebene aus. CharacterStyle
Die Spanne beeinflusst die Textdarstellung. UpdateAppearance
Die Spanne wirkt sich auf die Textmesswerte aus. UpdateLayout
Die Spanne wirkt sich auf den Text auf Absatzebene aus. ParagraphStyle

Wenn Sie z. B. eine benutzerdefinierte Spanne implementieren müssen, die die Textgröße und Farbe, RelativeSizeSpan erweitern. Durch Übernahme RelativeSizeSpan erweitert CharacterStyle und implementiert die beiden Update-Schnittstellen. Da diese gibt bereits Callbacks für updateDrawState und updateMeasureState an. können Sie diese Callbacks überschreiben, um Ihr benutzerdefiniertes Verhalten zu implementieren. Die Mit dem folgenden Code wird ein benutzerdefinierter Span erstellt, der RelativeSizeSpan und überschreibt den updateDrawState-Callback, um die Farbe von TextPaint festzulegen:

Kotlin

class RelativeSizeColorSpan(
    size: Float,
    @ColorInt private val color: Int
) : RelativeSizeSpan(size) {
    override fun updateDrawState(textPaint: TextPaint) {
        super.updateDrawState(textPaint)
        textPaint.color = color
    }
}

Java

public class RelativeSizeColorSpan extends RelativeSizeSpan {
    private int color;
    public RelativeSizeColorSpan(float spanSize, int spanColor) {
        super(spanSize);
        color = spanColor;
    }
    @Override
    public void updateDrawState(TextPaint textPaint) {
        super.updateDrawState(textPaint);
        textPaint.setColor(color);
    }
}

In diesem Beispiel wird gezeigt, wie Sie einen benutzerdefinierten Span erstellen. Das erreichen Sie auch indem Sie RelativeSizeSpan und ForegroundColorSpan auf den Text anwenden.

Span-Nutzung testen

Über die Spanned-Schnittstelle können Sie sowohl Spans festlegen als auch Spans aus folgenden Quellen abrufen: Text. Implementieren Sie beim Testen ein Android JUnit, Test, um zu prüfen, ob die richtigen Spans hinzugefügt wurden an den richtigen Stellen. Textstilbeispiel App enthält eine Span, die Markup auf Aufzählungspunkte anwendet, indem BulletPointSpan zum Text hinzufügen. Das folgende Codebeispiel zeigt, wie Sie ob die Aufzählungspunkte wie erwartet angezeigt werden:

Kotlin

@Test fun textWithBulletPoints() {
   val result = builder.markdownToSpans("Points\n* one\n+ two")

   // Check whether the markup tags are removed.
   assertEquals("Points\none\ntwo", result.toString())

   // Get all the spans attached to the SpannedString.
   val spans = result.getSpans<Any>(0, result.length, Any::class.java)

   // Check whether the correct number of spans are created.
   assertEquals(2, spans.size.toLong())

   // Check whether the spans are instances of BulletPointSpan.
   val bulletSpan1 = spans[0] as BulletPointSpan
   val bulletSpan2 = spans[1] as BulletPointSpan

   // Check whether the start and end indices are the expected ones.
   assertEquals(7, result.getSpanStart(bulletSpan1).toLong())
   assertEquals(11, result.getSpanEnd(bulletSpan1).toLong())
   assertEquals(11, result.getSpanStart(bulletSpan2).toLong())
   assertEquals(14, result.getSpanEnd(bulletSpan2).toLong())
}

Java

@Test
public void textWithBulletPoints() {
    SpannedString result = builder.markdownToSpans("Points\n* one\n+ two");

    // Check whether the markup tags are removed.
    assertEquals("Points\none\ntwo", result.toString());

    // Get all the spans attached to the SpannedString.
    Object[] spans = result.getSpans(0, result.length(), Object.class);

    // Check whether the correct number of spans are created.
    assertEquals(2, spans.length);

    // Check whether the spans are instances of BulletPointSpan.
    BulletPointSpan bulletSpan1 = (BulletPointSpan) spans[0];
    BulletPointSpan bulletSpan2 = (BulletPointSpan) spans[1];

    // Check whether the start and end indices are the expected ones.
    assertEquals(7, result.getSpanStart(bulletSpan1));
    assertEquals(11, result.getSpanEnd(bulletSpan1));
    assertEquals(11, result.getSpanStart(bulletSpan2));
    assertEquals(14, result.getSpanEnd(bulletSpan2));
}

Weitere Testbeispiele finden Sie unter MarkdownBuilderTest auf GitHub.

Benutzerdefinierte Spans testen

Prüfen Sie beim Testen von Spans, ob TextPaint die erwarteten Änderungen vorgenommen wurden und die richtigen Elemente auf deinem Canvas erscheinen. Für Stellen Sie sich eine benutzerdefinierte Span-Implementierung vor, bei der Text. Für den Aufzählungspunkt ist eine bestimmte Größe und Farbe angegeben und es entsteht eine Lücke. zwischen dem linken Rand des Zeichenbereichs und dem Aufzählungspunkt.

Sie können das Verhalten dieser Klasse testen, indem Sie einen AndroidJUnit-Test implementieren. Überprüfen Sie Folgendes:

  • Wenn Sie die Spanne korrekt angewendet haben, können Sie einen Aufzählungspunkt der angegebenen Größe und auf dem Canvas, und der korrekte Abstand zwischen der linken den Rand und den Aufzählungspunkt.
  • Wenn Sie den Span nicht anwenden, wird keines der benutzerdefinierten Funktionsweisen angezeigt.

Die Implementierung dieser Tests finden Sie unter TextStyling Beispiel auf GitHub.

Sie können Canvas-Interaktionen testen, indem Sie für den Canvas ein Mockup erstellen, das Objekt drawLeadingMargin() und überprüfen, ob die richtigen Methoden mit der richtigen Parameter.

Weitere Beispiele für Span-Test finden Sie unter BulletPointSpanTest definiert.

Best Practices für die Verwendung von Spans

Es gibt mehrere speichereffiziente Möglichkeiten, Text in einem TextView festzulegen, je nachdem, an Ihre Bedürfnisse anzupassen.

Spans anhängen oder entfernen, ohne den zugrunde liegenden Text zu ändern

TextView.setText() enthält mehrere Überlastungen, die Spans unterschiedlich verarbeiten. So können Sie zum Beispiel ein Spannable-Textobjekt mit dem folgenden Code festlegen:

Kotlin

textView.setText(spannableObject)

Java

textView.setText(spannableObject);

Beim Aufrufen dieser Überlastung von setText() erstellt TextView eine Kopie Ihrer Spannable als SpannedString und speichert sie als CharSequence. Das bedeutet, dass Ihr Text und die Spans unveränderlich sind. Aktualisieren Sie den Text oder die Spans, erstellen Sie ein neues Spannable-Objekt und rufen Sie setText() zurück. Dies löst ebenfalls eine erneute Messung und Neuzeichnung des Layout.

Um anzugeben, dass die Spans änderbar sein müssen, können Sie stattdessen setText(CharSequence text, TextView.BufferType type), Dies wird im folgenden Beispiel gezeigt:

Kotlin

textView.setText(spannable, BufferType.SPANNABLE)
val spannableText = textView.text as Spannable
spannableText.setSpan(
     ForegroundColorSpan(color),
     8, spannableText.length,
     SPAN_INCLUSIVE_INCLUSIVE
)

Java

textView.setText(spannable, BufferType.SPANNABLE);
Spannable spannableText = (Spannable) textView.getText();
spannableText.setSpan(
     new ForegroundColorSpan(color),
     8, spannableText.getLength(),
     SPAN_INCLUSIVE_INCLUSIVE);

In diesem Beispiel hat der Parameter BufferType.SPANNABLE erstellt TextView eine SpannableString und der Parameter Das von TextView beibehaltene CharSequence-Objekt verfügt jetzt über änderbares Markup und unveränderlicher Text. Rufen Sie zum Aktualisieren des Spans den Text als Spannable ab und Aktualisieren Sie die Spans nach Bedarf.

Wenn Sie Spans verbinden, trennen oder neu positionieren, TextView um die Textänderung widerzuspiegeln. Wenn Sie ein internes Attribut ändern eines vorhandenen Bereichs können Sie invalidate() aufrufen, um requestLayout(), um messwertbezogene Änderungen vorzunehmen.

Text in TextView mehrmals festlegen

In einigen Fällen, z. B. bei der Verwendung eines RecyclerView.ViewHolder, können Sie TextView wiederverwenden und den Text mehrmals festlegen. Von Unabhängig davon, ob Sie BufferType festlegen, erstellt die TextView Eine Kopie des CharSequence-Objekts und speichert es im Speicher. Damit sind alle TextView wird absichtlich aktualisiert. Das Original kann nicht aktualisiert werden. CharSequence-Objekts, um den Text zu aktualisieren. Das bedeutet, dass jedes Mal, wenn Sie Text eingeben, erstellt die TextView ein neues Objekt.

Wenn Sie diesen Prozess besser steuern und das zusätzliche Objekt vermeiden möchten können Sie Ihre eigenen Spannable.Factory und überschreiben newSpannable() Anstatt ein neues Textobjekt zu erstellen, können Sie das vorhandene CharSequence als Spannable, wie im folgenden Beispiel gezeigt:

Kotlin

val spannableFactory = object : Spannable.Factory() {
    override fun newSpannable(source: CharSequence?): Spannable {
        return source as Spannable
    }
}

Java

Spannable.Factory spannableFactory = new Spannable.Factory(){
    @Override
    public Spannable newSpannable(CharSequence source) {
        return (Spannable) source;
    }
};

Sie müssen textView.setText(spannableObject, BufferType.SPANNABLE) verwenden, wenn das Festlegen des Textes. Andernfalls wird die Quelle-CharSequence als Spanned erstellt. Instanz und kann nicht in Spannable umgewandelt werden, wodurch newSpannable() den Fehler ClassCastException

Nachdem Sie newSpannable() überschrieben haben, weisen Sie TextView an, die neue Factory zu verwenden:

Kotlin

textView.setSpannableFactory(spannableFactory)

Java

textView.setSpannableFactory(spannableFactory);

Legen Sie das Spannable.Factory-Objekt einmalig fest, nachdem Sie einen Verweis auf Ihre TextView. Wenn Sie ein RecyclerView verwenden, legen Sie das Factory-Objekt fest, wenn Sie die Anzahl der Aufrufe steigern. Dadurch wird die Erstellung zusätzlicher Objekte vermieden, RecyclerView bindet ein neues Element an ViewHolder.

Interne Span-Attribute ändern

Wenn Sie nur ein internes Attribut eines änderbaren Spans ändern müssen, z. B. das Aufzählungszeichenfarbe in benutzerdefinierten Aufzählungspunkten enthalten, können Sie vermeiden, dass das Aufrufen von setText() mehrfach ausführen, indem ein Verweis auf die Span bei der Erstellung beibehalten wird. Wenn Sie den Span ändern müssen, können Sie den Verweis ändern und dann invalidate() oder requestLayout() auf TextView, je nach Typ Attribut, das Sie geändert haben.

Im folgenden Codebeispiel enthält eine benutzerdefinierte Implementierung mit Aufzählungspunkten ein Standardfarbe Rot, die sich beim Antippen einer Schaltfläche in Grau ändert:

Kotlin

class MainActivity : AppCompatActivity() {

    // Keeping the span as a field.
    val bulletSpan = BulletPointSpan(color = Color.RED)

    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        val spannable = SpannableString("Text is spantastic")
        // Setting the span to the bulletSpan field.
        spannable.setSpan(
            bulletSpan,
            0, 4,
            Spanned.SPAN_INCLUSIVE_INCLUSIVE
        )
        styledText.setText(spannable)
        button.setOnClickListener {
            // Change the color of the mutable span.
            bulletSpan.color = Color.GRAY
            // Color doesn't change until invalidate is called.
            styledText.invalidate()
        }
    }
}

Java

public class MainActivity extends AppCompatActivity {

    private BulletPointSpan bulletSpan = new BulletPointSpan(Color.RED);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        SpannableString spannable = new SpannableString("Text is spantastic");
        // Setting the span to the bulletSpan field.
        spannable.setSpan(bulletSpan, 0, 4, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
        styledText.setText(spannable);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // Change the color of the mutable span.
                bulletSpan.setColor(Color.GRAY);
                // Color doesn't change until invalidate is called.
                styledText.invalidate();
            }
        });
    }
}

Funktionen der Android KTX-Erweiterung verwenden

Android KTX enthält außerdem Erweiterungsfunktionen, die die Arbeit mit Spans einfacher zu machen. Weitere Informationen finden Sie in der Dokumentation zum androidx.core.text Paket.