90

I am looking to change the text of a TextView view via the .setText("") method while also coloring a part of the text (or making it bold, italic, transparent, etc.)and not the rest. For example:

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

I know the above code is incorrect but it helps illustrate what I would like to achieve. How would I do this?

Mark
  • 2,380
  • 11
  • 29
  • 49
Jared
  • 4,823
  • 6
  • 23
  • 15
  • possible duplicate of [how can I change color part of a TextView?](http://stackoverflow.com/questions/4032676/how-can-i-change-color-part-of-a-textview) – live-love Aug 05 '15 at 13:59
  • If there is a long text in the TextView,There is [a more efficient way](http://stackoverflow.com/a/34449956/3414180) – Mingfei Dec 24 '15 at 09:02
  • Possible duplicate of [Set color of TextView span in Android](http://stackoverflow.com/questions/3282940/set-color-of-textview-span-in-android) – Suragch Jan 31 '17 at 07:16
  • Solution in Kotlin using Spans https://stackoverflow.com/a/59510004/11166067 – Dmitrii Leonov Dec 28 '19 at 10:45

15 Answers15

209

Use spans.

Example:

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);
JavierSA
  • 783
  • 1
  • 10
  • 25
Alex Orlov
  • 18,077
  • 7
  • 55
  • 44
  • 11
    I really do't like the solution android offers here, as it does not work with multi language as I have no idea how many chars in my words are. I'm currently looking for a solution where I can have multiple spans that I can attach all to a TextView and then they are put together – philipp Jul 24 '12 at 21:33
  • 1
    The comment saying span to make text bold, should it say span to make text color? – Ryhan Aug 01 '13 at 19:02
  • 9
    @philipp if your problem is how many characters in your word, use the length() method on your String or StringBuilder or whatever – Ahmed Adel Ismail Sep 23 '13 at 10:23
  • 1
    If there is a long text in the TextView, here is [a more efficient way](http://stackoverflow.com/a/34449956/3414180) – Mingfei Dec 24 '15 at 09:07
  • I initially missed this when reading the answer, but your end index has to be +1 the ending index in the string (i.e. to span first four letters you have to set [start, end] as [0, 4] not [0, 3] ) – tir38 May 19 '16 at 03:37
  • Why do you declare the first three variables as `final`? – l7r7 May 28 '16 at 12:24
  • Don't pay attention to it. I declare final any variable that is not supposed to change during method invocation – Alex Orlov May 31 '16 at 14:51
47
title.setText(Html.fromHtml("Your big island <b>ADVENTURE!</b>")); 
Nanne
  • 64,065
  • 16
  • 119
  • 163
sat
  • 40,138
  • 28
  • 93
  • 102
26

I hope this helps you (it works with multi language).

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

And on your java code, you can do:

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

This way, only the "Test" part will be colored (and bold).

Luis
  • 709
  • 8
  • 10
  • 3
    Best Answer. This works perfectly for internationalized strings. Also has the advantage of being able to have your colored text in the middle of your string resource. – jt-gilkeson Aug 01 '15 at 00:17
  • For further explanations see the **Styling with HTML markup** section [here](http://developer.android.com/guide/topics/resources/string-resource.html#FormattingAndStyling). – Eli Aug 03 '17 at 10:47
  • What makes the CDATA thing necessary? – Sarah Multitasker Jul 28 '21 at 10:42
22

If you are using Kotlin you can do the following using the android-ktx library

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

titleTextField.text = title

The bold is an extension function on SpannableStringBuilder. You can see the documentation here for a list of operations you can use.

Another example:

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

Where green is a resolved RGB color.

It is even possible to nest spans so you end up with something like an embedded DSL:

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

You will need the following in your app module level build.gradle for it to work:

repositories {
    google()
}

dependencies {
    implementation 'androidx.core:core-ktx:0.3'
}
Otziii
  • 2,304
  • 1
  • 25
  • 34
David Rawson
  • 20,912
  • 7
  • 88
  • 124
  • Also, no matter which color I put it, it shows same purple color. `val spannableStringBuilder = SpannableStringBuilder() spannableStringBuilder.bold { underline { color(R.color.test_color) { append(underlinedText) } } }` – Abhishek Saxena Apr 25 '20 at 04:37
17

Here's an example that will look for all occurrences of a word (case insensitive), and color them red:

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);
live-love
  • 48,840
  • 22
  • 240
  • 204
  • i love your name :P Can i change the background of specific word with new BackgroundColorSpan(Color.parseColor("#BFFFC6")) ? – Ajay Pandya Feb 13 '17 at 04:08
9

You can use a Spannable to give certain parts of a text certain aspects. I can look up an example if you want.

Ah, from right here on 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);
Community
  • 1
  • 1
Nanne
  • 64,065
  • 16
  • 119
  • 163
  • How can we configure start and end range for multi language text? – Mubarak Jul 30 '19 at 04:08
  • One idea could be to identify the word that you need to highlight and extract it as a separate string resource. When translating the phrase you will need to consider update the separate word also so that when you set the span to rely on the indexOf the string and string length to dynamically set the start and end indexes of the span. – Ionut Negru Nov 12 '20 at 07:58
4

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

or use this 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
  • 47
  • 2
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);
    }
}

Using

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

textView.setText(spannable);

enter image description here

Linh
  • 57,942
  • 23
  • 262
  • 279
4

If you want to use HTML, you need to use TextView.setText(Html.fromHtml(String htmlString))

If you want to do that often / repeatedly, you may have a look at a class (SpannableBuilder) I wrote, as Html.fromHtml() is not very efficient (it is using a big xml parsing machinery inside). It is described in this blog posting.

Heiko Rupp
  • 30,426
  • 13
  • 82
  • 119
4

I like to use SpannableStringBuilder by appending the different spans one by one, rather than calling setSpan by calculating the string lengths

as: (Kotlin code)

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

Result

Vedant Agarwala
  • 18,146
  • 4
  • 66
  • 89
2

You can concatenate two or more Spans. This way is easier to color dynamic text using length value.

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
  • 1,335
  • 11
  • 11
2

Use this code its helpful

TextView txtTest = (TextView) findViewById(R.id.txtTest);
txtTest.setText(Html.fromHtml("This is <font color="#ff4343">Red</font> Color!"));
Hadi Note
  • 1,386
  • 17
  • 16
1

You can use extension function in Kotlin

fun CharSequence.colorizeText(
    textPartToColorize: CharSequence,
    @ColorInt color: Int
): CharSequence = SpannableString(this).apply {
    val startIndexOfText = this.indexOf(textPartToColorize.toString())
    setSpan(ForegroundColorSpan(color), startIndexOfText, startIndexOfText.plus(textPartToColorize.length), 0)
}

Usage:

val colorizedText = "this text will be colorized"
val myTextToColorize = "some text, $colorizedText continue normal text".colorizeText(colorizedText,ContextCompat.getColor(context, R.color.someColor))
mtrakal
  • 6,121
  • 2
  • 25
  • 35
0

Html.fromHtml is deprecated

Use HtmlCompat instead

HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_LEGACY)
Gastón Saillén
  • 12,319
  • 5
  • 67
  • 77
0

If you do not want to get in trouble on lower SDK version use SpannableStringBuilder with ForegroundColorSpan or BackgroundColorSpan as HtmlCompat.fromHtml color style does not applied on older Android version.

Mihae Kheel
  • 2,441
  • 3
  • 14
  • 38