Android: coloration d'une partie d'une chaîne à l'aide de TextView.setText ()?

87

Je cherche à changer le texte d'une vue TextView via la méthode .setText ("") tout en colorant une partie du texte (ou en le rendant gras, italique, transparent, etc.) et pas le reste. Par exemple:

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

Je sais que le code ci-dessus est incorrect mais il aide à illustrer ce que je voudrais réaliser. Comment ferais-je cela?

Jared
la source
S'il y a un long texte dans TextView, il existe un moyen plus efficace
Mingfei
Double
Suragch
Solution à Kotlin utilisant Spans stackoverflow.com/a/59510004/11166067
Dmitrii Leonov

Réponses:

203

Utilisez des travées .

Exemple:

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
la source
11
Je n'aime vraiment pas la solution qu'offre Android ici, car elle ne fonctionne pas avec plusieurs langues car je n'ai aucune idée du nombre de caractères dans mes mots. Je cherche actuellement une solution où je peux avoir plusieurs travées que je peux attacher tout un TextView puis ils sont mis ensemble
philipp
1
Le commentaire disant span pour rendre le texte en gras, devrait-il indiquer span pour rendre le texte couleur?
Ryhan
9
@philipp si votre problème est de savoir combien de caractères dans votre mot, utilisez la méthode length () sur votre String ou StringBuilder ou autre
Ahmed Adel Ismail
1
S'il y a un long texte dans TextView, voici un moyen plus efficace
Mingfei
J'ai d'abord manqué cela lors de la lecture de la réponse, mais votre index de fin doit être +1 l'index de fin de la chaîne (c'est-à-dire que pour couvrir les quatre premières lettres, vous devez définir [début, fin] comme [0, 4] pas [0, 3])
tir38
46
title.setText(Html.fromHtml("Your big island <b>ADVENTURE!</b>")); 
Sam
la source
2
C'est une solution bien plus agréable au problème d'origine que la réponse marquée.
BSnapZ
1
Si vous avez des sauts de ligne \ n, cela n'affiche pas les sauts de ligne.
live-love
8
Non, ce n'est pas plus joli, il n'y a pas de coloration, mentionnée en question mais méthode SLOW fromHTML ()
Viktor Yakunin
1
Donc utiliser <font color="#FFAADD>text</font>ne fonctionnera pas?
milosmns
25

J'espère que cela vous aidera (cela fonctionne avec plusieurs langues).

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

Et sur votre code java, vous pouvez faire:

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

De cette façon, seule la partie "Test" sera colorée (et en gras).

Luis
la source
3
Meilleure réponse. Cela fonctionne parfaitement pour les chaînes internationalisées. A également l'avantage de pouvoir avoir votre texte coloré au milieu de votre ressource de chaîne.
jt-gilkeson
Pour plus d' explications voir le Styling avec de HTML section ici .
Elisabeth
17

Voici un exemple qui recherchera toutes les occurrences d'un mot (insensible à la casse) et les colorera en rouge:

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);
l'amour en direct
la source
j'aime votre nom: P Puis-je changer l'arrière-plan d'un mot spécifique avec le nouveau BackgroundColorSpan (Color.parseColor ("# BFFFC6"))?
Ajay Pandya
8

Vous pouvez utiliser a Spannablepour donner certains aspects à certaines parties d'un texte. Je peux chercher un exemple si vous le souhaitez.

Ah, à partir d'ici sur 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
la source
Comment pouvons-nous configurer la plage de début et de fin pour le texte multilingue?
Mubarak
Une idée pourrait être d'identifier le mot que vous devez mettre en évidence et de l'extraire en tant que ressource de chaîne distincte. Lors de la traduction de la phrase, vous devrez également envisager de mettre à jour le mot séparé afin que, lorsque vous définissez l'intervalle pour qu'il s'appuie sur l'indexOf, la chaîne et la longueur de la chaîne définissent dynamiquement les index de début et de fin de l'intervalle.
Ionut Negru
8

Si vous utilisez Kotlin, vous pouvez effectuer les opérations suivantes en utilisant la bibliothèque android-ktx

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

titleTextField.text = title

Il bolds'agit d'une fonction d'extension activée SpannableStringBuilder. Vous pouvez consulter la documentation ici pour une liste des opérations que vous pouvez utiliser.

Un autre exemple:

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

greenest une couleur RVB résolue.

Il est même possible d'imbriquer des travées pour vous retrouver avec quelque chose comme un DSL intégré:

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

Vous aurez besoin des éléments suivants dans le niveau de votre module d'application build.gradlepour que cela fonctionne:

repositories {
    google()
}

dependencies {
    implementation 'androidx.core:core-ktx:0.3'
}
David Rawson
la source
De plus, peu importe la couleur que je mets, il montre la même couleur violette. val spannableStringBuilder = SpannableStringBuilder() spannableStringBuilder.bold { underline { color(R.color.test_color) { append(underlinedText) } } }
Abhishek Saxena le
4

Si vous souhaitez utiliser du HTML, vous devez utiliser TextView.setText(Html.fromHtml(String htmlString))

Si vous voulez faire cela souvent / à plusieurs reprises, vous pouvez jeter un œil à une classe ( SpannableBuilder ) que j'ai écrite, car elle Html.fromHtml()n'est pas très efficace (elle utilise une grosse machine d'analyse XML à l'intérieur). Il est décrit dans cet article de blog .

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

En utilisant

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

textView.setText(spannable);

entrez la description de l'image ici

Phan Van Linh
la source
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 utilisez ce code:

    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
la source
3

J'aime utiliser SpannableStringBuilderen ajoutant les différentes étendues une par une, plutôt que d'appeler setSpan en calculant les longueurs de chaîne

comme: (code 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)
}

Résultat

védant
la source
2

Vous pouvez concaténer deux ou plusieurs travées. De cette façon, il est plus facile de colorer le texte dynamique en utilisant la valeur de longueur.

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
la source
2

Utilisez ce code, c'est utile

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

Html.fromHtmlest obsolète

Utilisez plutôt HtmlCompat

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