Android: colorare parte di una stringa utilizzando TextView.setText ()?


86

Sto cercando di modificare il testo di una visualizzazione TextView tramite il metodo .setText ("") colorando anche una parte del testo (o rendendolo grassetto, corsivo, trasparente, ecc.) E non il resto. Per esempio:

title.setText("Your big island <b>ADVENTURE!</b>";

So che il codice sopra non è corretto ma aiuta a illustrare ciò che vorrei ottenere. Come lo farei?



Se è presente un testo lungo in TextView, esiste un modo più efficiente
Mingfei


Soluzione in Kotlin utilizzando Spans stackoverflow.com/a/59510004/11166067
Dmitrii Leonov

Risposte:


202

Usa span .

Esempio:

final SpannableStringBuilder sb = new SpannableStringBuilder("your text here");

// Span to set text color to some RGB value
final ForegroundColorSpan fcs = new ForegroundColorSpan(Color.rgb(158, 158, 158)); 

// Span to make text bold
final StyleSpan bss = new StyleSpan(android.graphics.Typeface.BOLD); 

// Set the text color for first 4 characters
sb.setSpan(fcs, 0, 4, Spannable.SPAN_INCLUSIVE_INCLUSIVE); 

// make them also bold
sb.setSpan(bss, 0, 4, Spannable.SPAN_INCLUSIVE_INCLUSIVE); 

yourTextView.setText(sb);

11
Non mi piace davvero la soluzione che Android offre qui, in quanto non funziona con il multilingue perché non ho idea di quanti caratteri siano nelle mie parole. Attualmente sto cercando una soluzione in cui posso avere più intervalli che posso allegare tutti a un TextView e poi vengono messi insieme
philipp

1
Il commento che dice span per rendere il testo in grassetto, dovrebbe dire span per rendere il colore del testo?
Ryhan

9
@philipp se il tuo problema è il numero di caratteri nella tua parola, usa il metodo length () sul tuo String o StringBuilder o qualsiasi altra cosa
Ahmed Adel Ismail

1
Se è presente un testo lungo in TextView, ecco un modo più efficiente
Mingfei

Inizialmente mi sono perso questo durante la lettura della risposta, ma il tuo indice di fine deve essere +1 l'indice di fine nella stringa (ad esempio, per comprendere le prime quattro lettere devi impostare [inizio, fine] come [0, 4] non [0, 3])
tir38

46
title.setText(Html.fromHtml("Your big island <b>ADVENTURE!</b>")); 

2
Questa è una soluzione molto migliore al problema originale rispetto alla risposta contrassegnata.
BSnapZ

1
Se hai interruzioni di riga \ n, non vengono visualizzate le interruzioni di riga.
live-love

8
No, non è più bello, non c'è la funzione di colorazione, menzionata in questione ma il metodo SLOW daHTML ()
Viktor Yakunin

1
Quindi l'utilizzo <font color="#FFAADD>text</font>non funzionerà?
milosmns

25

Spero che questo ti aiuti (funziona con multilingua).

<string name="test_string" ><![CDATA[<font color="%1$s"><b>Test/b></font>]]> String</string>

E sul tuo codice java, puoi fare:

int color = context.getResources().getColor(android.R.color.holo_blue_light);
String string = context.getString(R.string.test_string, color);
textView.setText(Html.fromHtml(string));

In questo modo, solo la parte "Test" sarà colorata (e in grassetto).


3
Migliore risposta. Funziona perfettamente per le stringhe internazionalizzate. Ha anche il vantaggio di poter avere il tuo testo colorato al centro della tua risorsa stringa.
jt-gilkeson

Per ulteriori spiegazioni vedere la Styling con l'HTML markup sezione qui .
Elisabeth

17

Ecco un esempio che cercherà tutte le occorrenze di una parola (senza distinzione tra maiuscole e minuscole) e le colorerà di rosso:

String notes = "aaa AAA xAaax abc aaA xxx";
SpannableStringBuilder sb = new SpannableStringBuilder(notes);
Pattern p = Pattern.compile("aaa", Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher(notes);
while (m.find()){
    //String word = m.group();
    //String word1 = notes.substring(m.start(), m.end());

    sb.setSpan(new ForegroundColorSpan(Color.rgb(255, 0, 0)), m.start(), m.end(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
}
editText.setText(sb);

amo il tuo nome: P Posso cambiare lo sfondo di una parola specifica con il nuovo BackgroundColorSpan (Color.parseColor ("# BFFFC6"))?
Ajay Pandya

8

Puoi usare a Spannableper dare ad alcune parti di un testo certi aspetti. Posso cercare un esempio se vuoi.

Ah, da qui in poi stackoverflow .

TextView TV = (TextView)findViewById(R.id.mytextview01); 
Spannable WordtoSpan = new SpannableString("I know just how to whisper, And I know just how to cry,I know just where to find the answers");        
WordtoSpan.setSpan(new ForegroundColorSpan(Color.BLUE), 15, 30, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
TV.setText(WordtoSpan);

Come possiamo configurare l'intervallo iniziale e finale per il testo multilingue?
Mubarak

8

Se stai usando Kotlin puoi fare quanto segue usando la libreria android-ktx

val title = SpannableStringBuilder()
        .append("Your big island ")
        .bold { append("ADVENTURE") } 

titleTextField.text = title

La boldè una funzione estensione SpannableStringBuilder. Puoi vedere la documentazione qui per un elenco di operazioni che puoi usare.

Un altro esempio:

val ssb = SpannableStringBuilder()
            .color(green) { append("Green text ") }
            .append("Normal text ")
            .scale(0.5F) { append("Text at half size ") }
            .backgroundColor(green) { append("Background green") }

Dov'è greenun colore RGB risolto.

È anche possibile annidare gli intervalli in modo da ottenere qualcosa come un DSL incorporato:

bold { underline { italic { append("Bold and underlined") } } }

Avrai bisogno di quanto segue a livello di modulo della tua app build.gradleperché funzioni:

repositories {
    google()
}

dependencies {
    implementation 'androidx.core:core-ktx:0.3'
}

Inoltre, indipendentemente dal colore che ho messo, mostra lo stesso colore viola. val spannableStringBuilder = SpannableStringBuilder() spannableStringBuilder.bold { underline { color(R.color.test_color) { append(underlinedText) } } }
Abhishek Saxena il

4

Se vuoi usare HTML, devi usare TextView.setText(Html.fromHtml(String htmlString))

Se vuoi farlo spesso / ripetutamente, potresti dare un'occhiata a una classe ( SpannableBuilder ) che ho scritto, poiché Html.fromHtml()non è molto efficiente (utilizza un grande macchinario di analisi xml all'interno). È descritto in questo post sul blog .


4
public static void setColorForPath(Spannable spannable, String[] paths, int color) {
    for (int i = 0; i < paths.length; i++) {
        int indexOfPath = spannable.toString().indexOf(paths[i]);
        if (indexOfPath == -1) {
            continue;
        }
        spannable.setSpan(new ForegroundColorSpan(color), indexOfPath,
                indexOfPath + paths[i].length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    }
}

Utilizzando

Spannable spannable = new SpannableString("Your big island ADVENTURE");
Utils.setColorForPath(spannable, new String[] { "big", "ADVENTURE" }, Color.BLUE);

textView.setText(spannable);

inserisci qui la descrizione dell'immagine


3

            String str1 = "If I forget my promise to ";
            String penalty = "Eat breakfast every morning,";
            String str2 = " then I ";
            String promise = "lose my favorite toy";
           

            String strb = "<u><b><font color='#081137'>"+ penalty +",</font></b></u>";
            String strc = "<u><b><font color='#081137'>"+ promise + "</font></b></u>";
            String strd = str1 +strb+ str2 + strc;
           tv_notification.setText(Html.fromHtml(strd));

oppure usa questo codice:

    SpannableStringBuilder builder = new SpannableStringBuilder();
            SpannableString text1 = new SpannableString(str1);
            text1.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.silver)), 0, str1.length() - 1, 0);
            builder.append(text1);

            SpannableString text2 = new SpannableString(penalty);
            text2.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.midnight)), 0, penalty.length(), 0);
            text2.setSpan(new UnderlineSpan(), 0, penalty.length(), 0);
            builder.append(text2);

            SpannableString text3 = new SpannableString(str2);
            text3.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.silver)),0, str2.length(), 0);
            builder.append(text3);


            SpannableString text4 = new SpannableString(promise);
            text4.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.midnight)), 0, promise.length(), 0);
            text4.setSpan(new UnderlineSpan(),0, promise.length(), 0);
            builder.append(text4);

          tv_notification.setText(builder);


3

Mi piace usare SpannableStringBuilderaggiungendo i diversi intervalli uno per uno, piuttosto che chiamare setSpan calcolando le lunghezze delle stringhe

come: (codice Kotlin)

val amountSpannableString = SpannableString("₹$amount").apply {
  // text color
  setSpan(ForegroundColorSpan("#FD0025".parseColor()), 0, length, 0)
  // text size
  setSpan(AbsoluteSizeSpan(AMOUNT_SIZE_IN_SP.spToPx(context)), 0, length, 0)
  // font medium
  setSpan(TypefaceSpan(context.getString(R.string.font_roboto_medium)), 0, length, 0)
}

val spannable: Spannable = SpannableStringBuilder().apply {
  // append the different spans one by one
  // rather than calling setSpan by calculating the string lengths
  append(TEXT_BEFORE_AMOUNT)
  append(amountSpannableString)
  append(TEXT_AFTER_AMOUNT)
}

Risultato


2

È possibile concatenare due o più intervalli. In questo modo è più facile colorare il testo dinamico utilizzando il valore della lunghezza.

SpannableStringBuilder span1 = new SpannableStringBuilder("Android");
ForegroundColorSpan color1=new ForegroundColorSpan(getResources().getColor(R.color.colorPrimary));
span1.setSpan(color1, 0, span1.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);

SpannableStringBuilder span2 = new SpannableStringBuilder("Love");
ForegroundColorSpan color2=new ForegroundColorSpan(getResources().getColor(R.color.colorSecondary));
span2.setSpan(color2, 0, span2.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);

Spanned concatenated=(Spanned) TextUtils.concat(span1," => ",span2);

SpannableStringBuilder result = new SpannableStringBuilder(concatenated);

TextView tv = (TextView) rootView.findViewById(R.id.my_texview);
tv.setText(result, TextView.BufferType.SPANNABLE);

2

Usa questo codice è utile

TextView txtTest = (TextView) findViewById(R.id.txtTest);
txtTest.setText(Html.fromHtml("This is <font color="#ff4343">Red</font> Color!"));

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.