Jared
Jared

Reputation: 4983

Android: Coloring part of a string using TextView.setText()?

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?

Upvotes: 91

Views: 94394

Answers (15)

mtrakal
mtrakal

Reputation: 6407

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

Upvotes: 1

Mihae Kheel
Mihae Kheel

Reputation: 2641

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.

Upvotes: 0

Gast&#243;n Saill&#233;n
Gast&#243;n Saill&#233;n

Reputation: 13129

Html.fromHtml is deprecated

Use HtmlCompat instead

HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_LEGACY)

Upvotes: 0

David Rawson
David Rawson

Reputation: 21407

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

Upvotes: 25

Linh
Linh

Reputation: 60913

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

Upvotes: 4

Vedant Agarwala
Vedant Agarwala

Reputation: 18819

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

Upvotes: 4

Nur Gazi
Nur Gazi

Reputation: 47

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

Upvotes: 4

Hadi Note
Hadi Note

Reputation: 1414

Use this code its helpful

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

Upvotes: 2

Jorge Palacio
Jorge Palacio

Reputation: 1345

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

Upvotes: 2

Alex Orlov
Alex Orlov

Reputation: 18107

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

Upvotes: 210

live-love
live-love

Reputation: 52366

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

Upvotes: 17

Luis
Luis

Reputation: 739

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

Upvotes: 26

sat
sat

Reputation: 41076

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

Upvotes: 47

Nanne
Nanne

Reputation: 64399

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

Upvotes: 9

Heiko Rupp
Heiko Rupp

Reputation: 30934

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.

Upvotes: 4

Related Questions