在TextView中更改一个单词的文本颜色

106

我希望找到一种方法,在Activity中更改TextView中单词的颜色。

例如,使用以下代码:

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

我该如何将next文本的颜色更改为红色?

1
可能是在TextView中是否可以有多个样式?的重复问题。 - blahdiblah
https://dev59.com/y2kw5IYBdhLWcg3wn8CO#35271588 - Ciro Santilli OurBigBook.com
https://stackoverflow.com/a/59628947/12478830 - MMG
10个回答

187

我知道的最简单的方法就是使用HTML。

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

但这将需要您在想要更改颜色时重建TextView,这可能会引起麻烦。


1
这绝对是最简单的方法,但颜色不应该是color='#EE0000'吗?井号符号用于表示十六进制颜色。 - Tom
搞定了,谢谢!我不记得这是从实际的代码还是从记忆中复制的,可能之前并没有起作用。 - Dan
好的,只是确认一下!另外,我发现你不能使用8位十六进制代码,因此没有alpha组件。那个让我有点困惑。 - Tom
现在使用 fromHtml 已经被弃用。 - Ghasem
Html.fromHtml已经被弃用。这个解决方案对我很有用! - coderpc
显示剩余2条评论

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);
您需要使用Spannable,这样可以使一些文本变大、加粗等等,甚至可以插入一些图片。

4
好的回答,谢谢。在这种情况下,“s.length()”可以用来代替“start + next.length()”: int end = s.length(); - Oleg
2
如果有人在寻找Xamarin.Android解决方案,你可以使用控件的TextFormatted属性来分配SpannableString对象。 - Jamshaid K.
无法让它正常工作。最终采用了B K的解决方案。 - 2b77bee6-5445-4c77-b1eb-4df3e5
  1. 如果有可用的构建版本,最好使用它。
  2. 什么没有起作用?这个解决方案很老,非常老,一些API已经改变、添加、删除、修复了错误,到底是哪个部分无法正常工作?
- codeScriber
2
我遇到了“java.lang.String无法转换为android.text.Spannable”的错误。 - lashgar

45

像这样使用 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);

有没有什么东西可以替换 new ForegroundColorSpan(Color),使文本保留其原始默认颜色? - cjnash
如何在TextView中间添加纯文本(String)? - Ragavendra M

6
长字符串可以使用以下方式:
String help = getString(R.string.help);
help = help.replace("some word", "<font color='#EE0000'>some word</font>");
txtDesc.setText(Html.fromHtml(help));

3
如果你想要改变在一个 TextView 中的所有特定大小写不敏感的 String 实例的状态,可以像下面这样使用 StringBuilderSpannableString
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);

请将整个TextView文本存储在StringBuilder中。

将搜索的字符串存储在StringBuilder中。

将整个TextView文本存储在SpannableString中。

进行简单操作以查找TextView文本中的所有String实例,并在到达时更改它们。

TextView的文本值设置为SpannableString


2

使用:

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

功能:

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

我认为这种方法更易读,用于在字符串中着色一个单词。同时,它可能更加高效,因为你只需要写一次。

    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

我找到了这个最佳答案 https://dev59.com/8FkT5IYBdhLWcg3wf_lN#53573169 只需更改一行代码以支持首字母为大写的单词

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

1
我在Kotlin中实现了一个实用函数,适用于我的个人用例,也许对其他人有用。
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)
            }

我是如何使用它的:
context?.let {
        infoMessage.text = AppUtils.getCusomTextWithSpecificTextWithDiffColor(
                wordAsBold,
                completeSentence, ContextCompat.getColor(it, R.color.white))
    }

0

我的解决方案扩展:

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

使用方法

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接