Android: colorir parte de uma string usando TextView.setText ()?

86

Estou tentando alterar o texto de uma visualização TextView por meio do método .setText ("") enquanto também coloro uma parte do texto (ou tornando-o em negrito, itálico, transparente, etc.) e não o resto. Por exemplo:

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

Eu sei que o código acima está incorreto, mas ajuda a ilustrar o que eu gostaria de alcançar. Como eu faria isso?

Jared
fonte
possível duplicata de como posso alterar a parte da cor de um TextView?
live-love em
Se houver um texto longo no TextView, há uma maneira mais eficiente
Mingfei
Possível duplicata de Set color of TextView span no Android
Suragch
Solução em Kotlin usando Spans stackoverflow.com/a/59510004/11166067
Dmitrii Leonov

Respostas:

201

Use spans .

Exemplo:

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);
Alex Orlov
fonte
10
Eu realmente não gosto da solução que o android oferece aqui, já que não funciona com vários idiomas, pois não tenho ideia de quantos caracteres estão em minhas palavras. No momento, estou procurando por uma solução onde posso ter vários spans que posso anexar todos a um TextView e, em seguida, eles são colocados juntos
philipp
1
O comentário que diz span para tornar o texto em negrito, deve dizer span para tornar o texto colorido?
Ryhan 01 de
9
@philipp se o seu problema é quantos caracteres em sua palavra, use o método length () em sua String ou StringBuilder ou qualquer outro
Ahmed Adel Ismail
1
Se houver um texto longo no TextView, esta é uma maneira mais eficiente
Mingfei
Eu inicialmente perdi isso ao ler a resposta, mas seu índice final deve ser +1 o índice final da string (ou seja, para abranger as primeiras quatro letras, você deve definir [início, fim] como [0, 4] e não [0, 3])
tir38
46
title.setText(Html.fromHtml("Your big island <b>ADVENTURE!</b>")); 
Sentou
fonte
2
Esta é uma solução muito mais agradável para o problema original do que a resposta marcada.
BSnapZ
1
Se você tiver quebras de linha \ n, isso não exibe as quebras de linha.
live-love
8
Não, não é mais legal, não há recurso de colorir, mencionado em questão, mas o método SLOW deHTML ()
Viktor Yakunin
1
Então usar <font color="#FFAADD>text</font>não vai funcionar?
milosmns de
25

Espero que isso ajude você (funciona com vários idiomas).

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

E em seu código java, você pode fazer:

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

Desta forma, apenas a parte "Teste" ficará colorida (e em negrito).

Luis
fonte
3
Melhor resposta. Isso funciona perfeitamente para strings internacionalizadas. Também tem a vantagem de poder ter seu texto colorido no meio de seu recurso de string.
jt-gilkeson
Para obter mais explicações, consulte a seção Estilo com marcação HTML aqui .
Elisabeth
17

Aqui está um exemplo que procurará todas as ocorrências de uma palavra (não diferencia maiúsculas de minúsculas) e as colorirá de vermelho:

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);
amor ao vivo
fonte
Adoro o seu nome: P Posso mudar o fundo de uma palavra específica com o novo BackgroundColorSpan (Color.parseColor ("# BFFFC6"))?
Ajay Pandya
8

Você pode usar um Spannablepara dar certos aspectos a certas partes de um texto. Posso procurar um exemplo, se quiser.

Ah, daqui em diante 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);
Nanne
fonte
Como podemos configurar o intervalo inicial e final para texto multilíngue?
Mubarak
7

Se estiver usando Kotlin, você pode fazer o seguinte usando a biblioteca android-ktx

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

titleTextField.text = title

A boldé uma função de extensão on SpannableStringBuilder. Você pode ver a documentação aqui para uma lista de operações que você pode usar.

Outro exemplo:

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

Onde greenestá uma cor RGB resolvida.

É até possível aninhar spans para que você termine com algo como um DSL incorporado:

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

Você precisará do seguinte em seu nível de módulo de aplicativo build.gradlepara que ele funcione:

repositories {
    google()
}

dependencies {
    implementation 'androidx.core:core-ktx:0.3'
}
David Rawson
fonte
Além disso, não importa a cor que eu coloquei, ele mostra a mesma cor roxa. val spannableStringBuilder = SpannableStringBuilder() spannableStringBuilder.bold { underline { color(R.color.test_color) { append(underlinedText) } } }
Abhishek Saxena
4

Se você quiser usar HTML, você precisa usar TextView.setText(Html.fromHtml(String htmlString))

Se você quiser fazer isso com frequência / repetidamente, dê uma olhada em uma classe ( SpannableBuilder ) que escrevi, pois Html.fromHtml()não é muito eficiente (usa uma grande máquina de análise xml interna). É descrito nesta postagem do blog .

Heiko Rupp
fonte
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);
    }
}

Usando

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

textView.setText(spannable);

insira a descrição da imagem aqui

Phan Van Linh
fonte
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));

ou use este código:

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

Nur Gazi
fonte
3

Eu gosto de usar SpannableStringBuilderanexando os diferentes intervalos um por um, em vez de chamar setSpan calculando os comprimentos de string

como: (código 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)
}

Resultado

vedante
fonte
2

Você pode concatenar dois ou mais Spans. Desta forma, é mais fácil colorir o texto dinâmico usando o valor do comprimento.

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);
Jorge Palacio
fonte
2

Use este código é útil

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

Html.fromHtmlestá obsoleto

Em vez disso, use HtmlCompat

HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_LEGACY)
Gastón Saillén
fonte