211

As the title says, I want to know is it possible to achieve two different colored characters in a single textview element.

Swapnil Kotwal
  • 5,418
  • 6
  • 48
  • 92
Andro Selva
  • 53,910
  • 52
  • 193
  • 240
  • 3
    possible duplicate of [Is it possible to have multiple styles inside a TextView?](http://stackoverflow.com/questions/1529068/is-it-possible-to-have-multiple-styles-inside-a-textview) – dogbane May 23 '11 at 07:56
  • 2
    It's not duplicate since the asker is asking for color specifically. – Iqbal Mar 20 '17 at 11:07
  • There is a nice library for this, I think: https://blog.stylingandroid.com/rialto-downloadable-fonts/ https://github.com/StylingAndroid/Rialto – android developer Dec 25 '18 at 07:38
  • i have wrote some library too which having similar behaviour to this: https://github.com/ha-yi/MultiColorTextView – Hayi Nukman Aug 17 '19 at 12:44

23 Answers23

368

yes, if you format the String with html's font-color property then pass it to the method Html.fromHtml(your text here)

String text = "<font color=#cc0029>First Color</font> <font color=#ffcc00>Second Color</font>";
yourtextview.setText(Html.fromHtml(text));
Merthan Erdem
  • 5,598
  • 2
  • 22
  • 29
2red13
  • 11,197
  • 8
  • 40
  • 52
  • 11
    Don't forget to escape userinput using `Html.escapeHtml(str)`. – kelunik Jun 02 '13 at 13:44
  • nice solution.. but i want to ask is it for all android os version? – hitesh141 May 13 '15 at 10:04
  • I wish there was a way to do it without coding it. Not sure why something this simple is not implemented in T.V. – JPM Jun 26 '15 at 17:41
  • 3
    Just a warning. I was having an issue when I needed my text to be in uppercase. I was using android:textAllCaps="true" in XML and, at the same time, had my HTML content in uppercase. It wasn't working. I removed the XML attribute and it's now working fine. Be carefull, because if you use setAllCaps() in code, the same issue will appear. – joao2fast4u Dec 10 '15 at 11:21
  • 10
    `Html.fromHtml(String)` is now deprecated, instead use `Html.fromHtml(String, Html.FROM_HTML_MODE_LEGACY)`. [More information can be found here.](http://stackoverflow.com/questions/37904739/html-fromhtml-deprecated-in-android-n) – JediBurrell Feb 28 '17 at 04:26
192

You can prints lines with multiple colors without HTML as:

TextView textView = (TextView) findViewById(R.id.mytextview01);
Spannable word = new SpannableString("Your message");        

word.setSpan(new ForegroundColorSpan(Color.BLUE), 0, word.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

textView.setText(word);
Spannable wordTwo = new SpannableString("Your new message");        

wordTwo.setSpan(new ForegroundColorSpan(Color.RED), 0, wordTwo.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.append(wordTwo);
Thomas Vos
  • 12,271
  • 5
  • 33
  • 71
Swapnil Kotwal
  • 5,418
  • 6
  • 48
  • 92
  • great, thanks, also can do BackgroundColorSpan. there is a small typo in your example, WordToSpan and WordtoSpan, note the case on To – steveh Jul 01 '14 at 01:49
  • how does one go about unit testing the textview to ensure that the text ends in Color.RED http://stackoverflow.com/questions/26611533/how-to-get-spannable-from-textview-to-write-a-unit-test – sudocoder Oct 28 '14 at 14:59
  • 1
    Not working for me getting ` java.lang.StringIndexOutOfBoundsException: length=3; index=12` – Muhammad Babar Nov 26 '15 at 10:35
  • 2
    *StringIndexOutOfBoundsException* itself explanatory. You are accessing string beyond it's length. – Swapnil Kotwal Nov 26 '15 at 11:38
  • 1
    My strings were not fixed, so strings would generate at run time of the app. I have tried almost all the answers of this question. But only this solution worked for me. – Md. Sabbir Ahmed Apr 15 '19 at 04:37
42

I have done this way:

Check reference

Set Color on Text by passing String and color:

private String getColoredSpanned(String text, String color) {
    String input = "<font color=" + color + ">" + text + "</font>";
    return input;
}

Set text on TextView / Button / EditText etc by calling below code:

TextView:

TextView txtView = (TextView)findViewById(R.id.txtView);

Get Colored String:

String name = getColoredSpanned("Hiren", "#800000");
String surName = getColoredSpanned("Patel","#000080");

Set Text on TextView of two strings with different colors:

txtView.setText(Html.fromHtml(name+" "+surName));

Done

Hiren Patel
  • 52,124
  • 21
  • 173
  • 151
41

You can use Spannable to apply effects to your TextView:

Here is my example for colouring just the first part of a TextView text (while allowing you to set the color dynamically rather than hard coding it into a String as with the HTML example!)

    mTextView.setText("Red text is here", BufferType.SPANNABLE);
    Spannable span = (Spannable) mTextView.getText();
    span.setSpan(new ForegroundColorSpan(0xFFFF0000), 0, "Red".length(),
             Spannable.SPAN_INCLUSIVE_EXCLUSIVE);

In this example you can replace 0xFFFF0000 with a getResources().getColor(R.color.red)

Graeme
  • 25,714
  • 24
  • 124
  • 186
35

Use SpannableStringBuilder

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);
Biswajit Karmakar
  • 9,799
  • 4
  • 39
  • 41
12

I have done this, try it:

TextView textView=(TextView)findViewById(R.id.yourTextView);//init

//here I am appending two string into my textView with two diff colors.
//I have done from fragment so I used here getActivity(), 
//If you are trying it from Activity then pass className.this or this; 

textView.append(TextViewUtils.getColoredString(getString(R.string.preString),ContextCompat.getColor(getActivity(),R.color.firstColor)));
textView.append(TextViewUtils.getColoredString(getString(R.string.postString),ContextCompat.getColor(getActivity(),R.color.secondColor)));

Inside your TextViewUtils class add this method:

 /***
 *
 * @param mString this will setup to your textView
 * @param colorId  text will fill with this color.
 * @return string with color, it will append to textView.
 */
public static Spannable getColoredString(String mString, int colorId) {
    Spannable spannable = new SpannableString(mString);
    spannable.setSpan(new ForegroundColorSpan(colorId), 0, spannable.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    Log.d(TAG,spannable.toString());
    return spannable;
}
peterh
  • 11,875
  • 18
  • 85
  • 108
Abdul Rizwan
  • 3,904
  • 32
  • 31
10

It's better to use the string in the strings file, as such:

    <string name="some_text">
<![CDATA[
normal color <font color=\'#06a7eb\'>special color</font>]]>
    </string>

Usage:

textView.text=HtmlCompat.fromHtml(getString(R.string.some_text), HtmlCompat.FROM_HTML_MODE_LEGACY)
android developer
  • 114,585
  • 152
  • 739
  • 1,270
8

Kotlin version of @Swapnil Kotwal's answer.

Android Studio 4.0.1, Kotlin 1.3.72

val greenText = SpannableString("This is green,")
greenText.setSpan(ForegroundColorSpan(resources.getColor(R.color.someGreenColor), null), 0, greenText.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
yourTextView.text = greenText

val yellowText = SpannableString("this is yellow, ")
yellowText.setSpan(ForegroundColorSpan(resources.getColor(R.color.someYellowColor), null), 0, yellowText.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
yourTextView.append(yellowText)

val redText = SpannableString("and this is red.")
redText.setSpan(ForegroundColorSpan(resources.getColor(R.color.someRedColor), null), 0, redText.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
yourTextView.append(redText)
Dan Abnormal
  • 1,188
  • 11
  • 21
8

I don't know, since when this is possible, but you can simply add <font> </font> to your string.xml which will automatically change the color per text. No need to add any additional code such as spannable text etc.

Example

<string name="my_formatted_text">
    <font color="#FF0707">THIS IS RED</font>
    <font color="#0B132B">AND NOW BLUE</font>
</string>
Andrew
  • 4,264
  • 1
  • 21
  • 65
6

I have write down some code for other question which is similar to this one, but that question got duplicated so i can't answer there so i am just putting my code here if someone looking for same requirement.

It's not fully working code, you need to make some minor changes to get it worked.

Here is the code:

I've used @Graeme idea of using spannable text.

String colorfulText = "colorfulText";       
    Spannable span = new SpannableString(colorfulText);             

    for ( int i = 0, len = colorfulText.length(); i < len; i++ ){
        span.setSpan(new ForegroundColorSpan(getRandomColor()), i, i+1,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);                     
    }   

    ((TextView)findViewById(R.id.txtSplashscreenCopywrite)).setText(span);

Random Color Method:

  private int getRandomColor(){
        Random rnd = new Random();
        return Color.argb(255, rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));
    }
NaserShaikh
  • 1,576
  • 2
  • 23
  • 39
5

Using Kotlin and Extensions you can add colored text really easy and clean:

Create a file TextViewExtensions.kt with this content

fun TextView.append(string: String?, @ColorRes color: Int) {
    if (string == null || string.isEmpty()) {
        return
    }

    val spannable: Spannable = SpannableString(string)
    spannable.setSpan(
        ForegroundColorSpan(ContextCompat.getColor(context, color)),
        0,
        spannable.length,
        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
    )

    append(spannable)
}

Now is really easy to append text with color

textView.text = "" // Remove old text
textView.append("Red Text", R.color.colorAccent)
textView.append("White Text", android.R.color.white)

Basically is same as @Abdul Rizwan answer but using Kotlin, extensions, some validations and getting color inside extension.

Kenny Orellana
  • 500
  • 4
  • 7
4

Kotlin Answer

fun setTextColor(tv:TextView, startPosition:Int, endPosition:Int, color:Int){
    val spannableStr = SpannableString(tv.text)

    val underlineSpan = UnderlineSpan()
    spannableStr.setSpan(
        underlineSpan,
        startPosition,
        endPosition,
        Spanned.SPAN_INCLUSIVE_EXCLUSIVE
    )

    val backgroundColorSpan = ForegroundColorSpan(this.resources.getColor(R.color.agreement_color))
    spannableStr.setSpan(
        backgroundColorSpan,
        startPosition,
        endPosition,
        Spanned.SPAN_INCLUSIVE_EXCLUSIVE
    )

    val styleSpanItalic = StyleSpan(Typeface.BOLD)
    spannableStr.setSpan(
        styleSpanItalic,
        startPosition,
        endPosition,
        Spanned.SPAN_INCLUSIVE_EXCLUSIVE
    )

    tv.text = spannableStr
}

After, call above function. You can call more than one:

setTextColor(textView, 0, 61, R.color.agreement_color)
setTextColor(textView, 65, 75, R.color.colorPrimary)

Output: You can see underline and different colors with each other.

canerkaseler
  • 6,204
  • 45
  • 38
4

If you want to give text color and text size in strings.xml then check out the below code:

<string name="txt_my_string">
    <font fgcolor='#CFD8DC' > Text with given color </font> // Custom text color
    <font size="14" > Text with given size </font> // Custom Text size
    <font fgcolor='#3A55EA' size="14" > Text with given color and size </font> // Custom text color and size
</string>

Hope you understand easily :)

Jaydeep parmar
  • 561
  • 2
  • 15
3

Try this:

mBox = new TextView(context);
mBox.setText(Html.fromHtml("<b>" + title + "</b>" +  "<br />" + 
      "<small>" + description + "</small>" + "<br />" + 
      "<small>" + DateAdded + "</small>"));
AJPerez
  • 3,435
  • 10
  • 61
  • 91
Hurab
  • 169
  • 1
  • 4
2

Use SpannableBuilder class instead of HTML formatting where it possible because it more faster then HTML format parsing. See my own benchmark "SpannableBuilder vs HTML" on Github Thanks!

Anatolii Shuba
  • 4,614
  • 1
  • 16
  • 17
2

Awesome answers! I was able to use Spannable to build rainbow colored text (so this could be repeated for any array of colors). Here's my method, if it helps anyone:

private Spannable buildRainbowText(String pack_name) {
        int[] colors = new int[]{Color.RED, 0xFFFF9933, Color.YELLOW, Color.GREEN, Color.BLUE, Color.RED, 0xFFFF9933, Color.YELLOW, Color.GREEN, Color.BLUE, Color.RED, 0xFFFF9933, Color.YELLOW, Color.GREEN, Color.BLUE, Color.RED, 0xFFFF9933, Color.YELLOW, Color.GREEN, Color.BLUE};
        Spannable word = new SpannableString(pack_name);
        for(int i = 0; i < word.length(); i++) {
            word.setSpan(new ForegroundColorSpan(colors[i]), i, i+1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
        return word;
    }

And then I just setText(buildRainboxText(pack_name)); Note that all of the words I pass in are under 15 characters and this just repeats 5 colors 3 times - you'd want to adjust the colors/length of the array for your usage!

Casey Murray
  • 1,582
  • 17
  • 21
1
if (Build.VERSION.SDK_INT >= 24) {
     Html.fromHtml(String, flag) // for 24 API  and more
 } else {
     Html.fromHtml(String) // or for older API 
 }

for 24 API and more (flag)

public static final int FROM_HTML_MODE_COMPACT = 63;
public static final int FROM_HTML_MODE_LEGACY = 0;
public static final int FROM_HTML_OPTION_USE_CSS_COLORS = 256;
public static final int FROM_HTML_SEPARATOR_LINE_BREAK_BLOCKQUOTE = 32;
public static final int FROM_HTML_SEPARATOR_LINE_BREAK_DIV = 16;
public static final int FROM_HTML_SEPARATOR_LINE_BREAK_HEADING = 2;
public static final int FROM_HTML_SEPARATOR_LINE_BREAK_LIST = 8;
public static final int FROM_HTML_SEPARATOR_LINE_BREAK_LIST_ITEM = 4;
public static final int FROM_HTML_SEPARATOR_LINE_BREAK_PARAGRAPH = 1;
public static final int TO_HTML_PARAGRAPH_LINES_CONSECUTIVE = 0;
public static final int TO_HTML_PARAGRAPH_LINES_INDIVIDUAL = 1;

More Info

Ahmad Aghazadeh
  • 16,571
  • 12
  • 101
  • 98
1

Since API 24 you have FROM_HTML_OPTION_USE_CSS_COLORS so you can define colors in CSS instead of repeating it all time with font color=" Much clearer - when you have some html and you want to highlight some predefined tags - you just need to add CSS fragment at top of your html

Filipkowicz
  • 639
  • 6
  • 17
0

Make common funtion for convert your string spannable like this.

//pass param textviewid ,start,end,string
//R.color.Red it's your color you can change it as requirement

fun SpannableStringWithColor(view: TextView,start:Int,end:Int, s: String) {
    val wordtoSpan: Spannable =
        SpannableString(s)
    wordtoSpan.setSpan(
        ForegroundColorSpan(ContextCompat.getColor(view.context, R.color.Red)),
        start,
        end,
        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
    )
    view.text = wordtoSpan
    }

We can use anywhere as requirement like this.

 SpannableStringWithColor(tvMobileNo,0,14,"Mobile Number :   " + "123456789")

 SpannableStringWithColor(tvEmail,0,5,"Email :   " + "abc@gmail.com" "))

 SpannableStringWithColor(tvAddress,0,8,"Address :   " + "Delhi India")
Umesh Yadav
  • 1,042
  • 9
  • 17
0

Builder function in Kotlin:

  val text = buildSpannedString {
      append("My red text")
      setSpan(
          ForegroundColorSpan(ContextCompat.getColor(requireContext(), R.color.red)),
          3,
          6,
          Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
      )
  }
  textView?.setText(text)
Yeldar Nurpeissov
  • 1,786
  • 14
  • 19
0

for kotlin:

@JvmStatic
    @BindingAdapter(
        "app:txt1",
        "app:txt2",
        "app:color1",
        "app:color2",
        requireAll = false
    )
    fun setColors(
        txtView: AppCompatTextView,
        txt1: String,
        txt2: String,
        color1: Int,
        color2: Int
    ) {
        txtView.setColors(txt1 = txt1, txt2 = txt2, color1 = color1, color2)
    }


fun AppCompatTextView.setColors(txt1: String, txt2: String, color1: Int, color2: Int) {


        val word: Spannable = SpannableString(txt1)

        word.setSpan(
            ForegroundColorSpan(ContextCompat.getColor(this.context, color1)),
            0,
            word.length,
            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
        )

        this.text = word
        val wordTwo: Spannable = SpannableString(txt2)

        wordTwo.setSpan(
            ForegroundColorSpan(ContextCompat.getColor(this.context, color2)),
            0,
            wordTwo.length,
            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
        )
        this.append(wordTwo)

    }


<androidx.appcompat.widget.AppCompatTextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:txt1="@{}"
            app:txt2="@{}"
            app:color1="@{}"
            app:color2="@{}" />
tohidmahmoudvand
  • 256
  • 2
  • 14
0

Best to use Spannable to change the color and use Regex to find the text you want to change. I do not recommend using HtmlCompat because it modifies the structure of the text.

When you modify the text add

textView.setText("textExample", BufferType.SPANNABLE)

Prepare the regular expression and color

val regex = Regex("Example")
val color = ContextCompat.getColor(requireContext(), R.color.red)

I also recommend that you create a function to make it simpler

private fun applyTint(textView:TextView, regex:Regex, intColor:Int) {

    val span : Spannable = textView.text.toSpannable()
    val values = regex.findAll(textView.text)

    for(value in values.iterator()){
        val range = value.range
        span.setSpan(
            ForegroundColorSpan(intColor),
            range.first,
            range.last+1,
            Spannable.SPAN_COMPOSING
        )
    }
}

And finally call you funtion

applyTint(textView, regex, color)

The result is this:

CodeResult

If you need more information about regular expressions consult the documentation https://developer.android.com/reference/java/util/regex/Pattern#summary-of-regular-expression-constructs

Mixdor
  • 11
  • 1
0

If subscription = none, it shows the status "Active," otherwise "Inactive."

if (it.data?.memberInfo?.subscription == "none") {
        val text = "<font color=#4d4d4d>Status: </font> <font color=#EB5757>Inactive</font>"
        binding.status.text = HtmlCompat.fromHtml(text, HtmlCompat.FROM_HTML_MODE_LEGACY)
    } else {
        val text = "<font color=#4d4d4d>Status: </font> <font color=#00AA0E>Active</font>"
        binding.status.text = HtmlCompat.fromHtml(text, HtmlCompat.FROM_HTML_MODE_LEGACY)
    }

Output:enter image description here

Maruf Alam
  • 228
  • 4
  • 10