106

I am looking for a way to change the color of a text of a single word in a TextView from within an Activity.

For example, with this:

String first = "This word is ";
String next = "red"
TextView t = (TextView) findViewById(R.id.textbox);
t.setText(first + next);

How would I change the color of the next text to red?

3

11 Answers 11

187

Easiest way I know is to just use html.

String first = "This word is ";
String next = "<font color='#EE0000'>red</font>";
t.setText(Html.fromHtml(first + next));

But this will require you to rebuild the TextView when (if?) you want to change the color, which could cause a hassle.

7
  • 1
    This is definitely the simplest way but shouldn't the color be color='#EE0000' the pound symbol is needed to denote a hexadecimal color.
    – Tom
    Commented May 13, 2012 at 14:36
  • Fixed, thanks! I don't recall if I copied this from actual code or from memory with a color generator website so it might not have worked before.
    – Dan
    Commented May 14, 2012 at 19:16
  • Ok just making sure! Also, as I found out you cannot use 8-digit hex codes so no alpha component. That one stumped me for a moment.
    – Tom
    Commented May 15, 2012 at 0:15
  • Using fromHtml is deprecated now
    – Ghasem
    Commented Apr 16, 2017 at 6:19
  • Html.fromHtml is deprecated. This solution worked for me!
    – krsna
    Commented Jul 27, 2017 at 1:03
79
t.setText(first + next, BufferType.SPANNABLE);
Spannable s = (Spannable)t.getText();
int start = first.length();
int end = start + next.length();
s.setSpan(new ForegroundColorSpan(0xFFFF0000), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

you have to use spannable this will also allows you to increase some text's size, make it bold etc.... even put in some image.

5
  • 4
    Good answer, thanks. In this case "s.length()" can be used instead of "start + next.length()": int end = s.length();
    – Oleg
    Commented Aug 8, 2014 at 14:27
  • 2
    In case anyone looking for Xamarin.Android Solution. You can assign SpannableString object by using TextFormatted Property of your control. Commented May 5, 2017 at 15:48
  • Could not get this working. Ended up going with B K's solution. Commented Jun 5, 2017 at 15:35
  • 1. if there is a build it's always better to use it. 2. what didn't work for u ? this solution is old, very old, some apis have changed, added, removed, bug fixed, what exactly failed to work ? Commented Jun 10, 2017 at 19:03
  • 2
    I get java.lang.String cannot be cast to android.text.Spannable error.
    – lashgar
    Commented Dec 5, 2018 at 8:10
45

Use SpannableStringBuilder like this :

SpannableStringBuilder builder = new SpannableStringBuilder();

SpannableString str1= new SpannableString("Text1");
str1.setSpan(new ForegroundColorSpan(Color.RED), 0, str1.length(), 0);
builder.append(str1);

SpannableString str2= new SpannableString(appMode.toString());
str2.setSpan(new ForegroundColorSpan(Color.GREEN), 0, str2.length(), 0);
builder.append(str2);

TextView tv = (TextView) view.findViewById(android.R.id.text1);
tv.setText( builder, TextView.BufferType.SPANNABLE);
2
  • Is there something I can replace new ForegroundColorSpan(Color) with to make the text retain its original default color?
    – cjnash
    Commented Jul 31, 2017 at 18:52
  • How to add plain text(String) in middle of textview ? Commented Dec 26, 2018 at 10:10
6

for long string you can use this:

String help = getString(R.string.help);
help = help.replace("some word", "<font color='#EE0000'>some word</font>");
txtDesc.setText(Html.fromHtml(help));
3

If you want to change the state of all the instances of a specific String inside a TextView text(case insensitive) you can use StringBuilders and SpannableString like this:

StringBuilder textBuilder = new StringBuilder(myTextView.getText().toString());
StringBuilder searchedTextBuilder = new StringBuilder((mySearchedString));
SpannableString spannableString = new SpannableString(myTextView.getText().toString());

int counter = 0;
int index = 0;

for (int i = 0;i < textBuilder.length() - mySearchedString.length() - 1;i++)
{
    counter = 0;
    if (Character.toLowerCase(textBuilder.charAt(i)) == Character.toLowerCase(searchedTextBuilder.charAt(index)))
    {
        counter++;
        index++;
        for (int j = 1,z = i + 1;j < mySearchedString.length() - 1;j++,z++)
        {
            if (Character.toLowerCase(textBuilder .charAt(z)) == Character.toLowerCase(searchedTextBuilder .charAt(index)))
            {
                counter++;
                index++;
            }
            else
            {
                index++;
                if (index % mySearchedString.length() == 0)
                {
                    index = 0;
                }
                break;
             }
        }
        if (counter == mySearchedString.length() - 1) // A match
        {
            spannableString.setSpan(new ForegroundColorSpan(Color.RED), i,
                                i + mySearchedString.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); // Do the change you want(In this case changing the fore ground color to red)
            index = 0;
            continue;
        }
        else
        {
            index = 0;
            continue;
        }
    }
}
myTextView.setText(spannableString);

}

  • Store the whole TextView text inside a StringBuilder.
  • Store the searched string inside a StringBuilder.
  • Store the wholre TextView text inside a SpannableString
  • Make a simple operation to find all the String instances inside the TextView text and change them when reached.
  • Set the text value of the TextView to the SpannableString.
2

USE:

makeTextBold("Your order is accepted","accepted", textView);
makeTextBold("Your order is canceled","canceled", textView);

Function:

public static void makeTextBold(String sentence, String word, AppCompatTextView textView) {
    SpannableStringBuilder builder = new SpannableStringBuilder();
    int startIndex = sentence.indexOf(word.toLowerCase().trim());
    int endIndex = startIndex + word.toLowerCase().trim().length();
    SpannableString spannableString = new SpannableString(sentence);
    StyleSpan boldSpan = new StyleSpan(Typeface.BOLD);
    spannableString.setSpan(boldSpan, startIndex, endIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); //To make text Bold
    spannableString.setSpan(new ForegroundColorSpan(Color.RED), startIndex, endIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); //To change color of text
    builder.append(spannableString);
    textView.setText(builder, TextView.BufferType.SPANNABLE);
}
2

I think this is more readable for coloring a word in a string it is also probably more efficient a bit because you write once

    String str  = YOUR_STRING
    Spannable s = new SpannableString(str);
    int start = str.indexOf(err_word_origin);
    int end =  start + err_word_origin.length();
    s.setSpan(new ForegroundColorSpan(Color.BLUE), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    YOUR_TEXT_VIEW.setText(s , TextView.BufferType.SPANNABLE);
1

I implemented a utility function in Kotlin for my own usecase and maybe useful for someone else.

fun getCusomTextWithSpecificTextWithDiffColor(textToBold: String, fullText: String,
                                                  targetColor: Int) =
            SpannableStringBuilder(fullText).apply {
                setSpan(ForegroundColorSpan(targetColor),
                        fullText.indexOf(textToBold),
                        (fullText.indexOf(textToBold) + textToBold.length),
                        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
            }

How I am using it:

context?.let {
        infoMessage.text = AppUtils.getCusomTextWithSpecificTextWithDiffColor(
                wordAsBold,
                completeSentence, ContextCompat.getColor(it, R.color.white))
    }
1

Iv'e found this best answer https://stackoverflow.com/a/53573169/14250778 just changed one line to support also words that starts with uppercase letter

public void setHighLightedText(TextView tv, String textToHighlight) {
        // added "toLowerCase()" to support words that starts with uppercase letter
        String tvt = tv.getText().toString().toLowerCase();
        int ofe = tvt.indexOf(textToHighlight, 0);
        Spannable wordToSpan = new SpannableString(tv.getText());
        for (int ofs = 0; ofs < tvt.length() && ofe != -1; ofs = ofe + 1) {
            ofe = tvt.indexOf(textToHighlight, ofs);
            if (ofe == -1)
                break;
            else {
                // set color here
                wordToSpan.setSpan(new BackgroundColorSpan(0xFFFFFF00), ofe, ofe + textToHighlight.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                tv.setText(wordToSpan, TextView.BufferType.SPANNABLE);
            }
        }
    }
0

my solution extension:

    fun coloredText(
    baseText: String,
    coloredText: String,
    targetColor: Int
): SpannableStringBuilder {
    val transformText = "$baseText $coloredText"
    return SpannableStringBuilder(transformText).apply {
        setSpan(
            ForegroundColorSpan(targetColor),
            transformText.indexOf(coloredText),
            (transformText.indexOf(coloredText) + coloredText.length),
            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
        )
    }
}

Usage

binding.mytextView.title = coloredText(
            baseText = getString(R.string.my_title),
            coloredText = getString(R.string.my_title_colored_part),
            targetColor = ContextCompat.getColor(requireContext(), R.color.blue))
0

You could go this easy:

<string>what ever <font color="#121212">IMPORTANT</font> text you want </string>

For a result like this:

enter image description here

You then could use more of the resources for strings, such as bold, italics or others supported.

https://developer.android.com/guide/topics/resources/string-resource

I'm new to android... but you guys put too much effort and little documentation for such small things.

Not the answer you're looking for? Browse other questions tagged or ask your own question.