在安卓中设置TextView span的颜色

244

如何在TextView中只设置部分文本的颜色?

我想要做类似Twitter应用的效果,其中一部分文本是蓝色的。请参见下面的图像:

alt text
(来源: twimg.com)

20个回答

496

另一个答案非常相似,但不需要两次设置TextView的文本

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

1
但是我如何更改整个文本中多个单词的颜色,而不仅仅是一个 span? - mostafa hashim
2
@mostafahashim 通过重复第3行wordtoSpan.setSpan(new ForegroundColorSpan(Color.RED), 50, 80, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);来创建多个跨度。 - Ashraf Alshahawy
Kotlin + Spannable String 的解决方案如下所示:https://dev59.com/Qm865IYBdhLWcg3wA5yc#59510004 - Dmitrii Leonov

93

这是一个小帮助函数,非常适合在多种语言之间切换时使用!

private void setColor(TextView view, String fulltext, String subtext, int color) {
    view.setText(fulltext, TextView.BufferType.SPANNABLE);
    Spannable str = (Spannable) view.getText();
    int i = fulltext.indexOf(subtext);
    str.setSpan(new ForegroundColorSpan(color), i, i + subtext.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}

51

当我尝试理解新概念时,视觉示例总是很有帮助的。

背景颜色

输入图像描述

SpannableString spannableString = new SpannableString("Hello World!");
BackgroundColorSpan backgroundSpan = new BackgroundColorSpan(Color.YELLOW);
spannableString.setSpan(backgroundSpan, 0, spannableString.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(spannableString);

前景色

这里输入图像描述

SpannableString spannableString = new SpannableString("Hello World!");
ForegroundColorSpan foregroundSpan = new ForegroundColorSpan(Color.RED);
spannableString.setSpan(foregroundSpan, 0, spannableString.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(spannableString);

组合

在此输入图片描述

SpannableString spannableString = new SpannableString("Hello World!");
ForegroundColorSpan foregroundSpan = new ForegroundColorSpan(Color.RED);
BackgroundColorSpan backgroundSpan = new BackgroundColorSpan(Color.YELLOW);
spannableString.setSpan(foregroundSpan, 0, 8, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
spannableString.setSpan(backgroundSpan, 3, spannableString.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(spannableString);

进一步学习


@GkMohammadEmon,这听起来像是自定义绘画而不是简单的背景颜色。请查看贝塞尔曲线。 - Suragch
你有关于这方面的好参考资料或资源吗?我需要为我的通知操作按钮添加一个曲线背景。感谢您的回复。 - Gk Mohammad Emon
@GkMohammadEmon,抱歉我不知道。自从我转向Flutter后,已经有一段时间没有在Android中进行自定义绘制了。 - Suragch

33

如果你想要更多的控制权,你可能需要查看 TextPaint 类。以下是使用方法:

final ClickableSpan clickableSpan = new ClickableSpan() {
    @Override
    public void onClick(final View textView) {
        //Your onClick code here
    }

    @Override
    public void updateDrawState(final TextPaint textPaint) {
        textPaint.setColor(yourContext.getResources().getColor(R.color.orange));
        textPaint.setUnderlineText(true);
    }
};

getColor(int id)在Android 6.0 Marshmallow (API 23)上已被弃用。https://dev59.com/HlwZ5IYBdhLWcg3wVO9U - Eka putra
带有点击监听器的好回答。 - Muhaiminur Rahman

23

将您的TextView的文本设置为可跨度,并为文本定义一个ForegroundColorSpan

TextView textView = (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);    
textView.setText(wordtoSpan);

谢谢!不将文本先分配给TextView,这样做是否可行? - hpique
我没有解释清楚。让我重新表述一下。前三行是必要的吗?你不能直接从字符串创建Spannable对象吗? - hpique
不,你必须将TextView的文本存储到一个Buffer Spannable中才能更改前景色。 - Jorgesys
我想对颜色做同样的事情,而且我希望所有内容都加粗,除了有颜色的部分,那部分我想要斜体,我该如何做到这一点? - Lukap
1
如何在 span 中设置点击事件? - Rishabh Srivastava

15

在某些情况下可以使用另一种方法,即将链接颜色设置为采用Spannable的视图的属性。

例如,如果要在TextView中使用Spannable,则可以像这样在XML中设置链接颜色:

<TextView
    android:id="@+id/myTextView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textColorLink="@color/your_color"
</TextView>
您也可以在代码中设置它:
TextView tv = (TextView) findViewById(R.id.myTextView);
tv.setLinkTextColor(your_color);

12

这是我为此编写的 Kotlin 扩展函数

    fun TextView.setColouredSpan(word: String, color: Int) {
        val spannableString = SpannableString(text)
        val start = text.indexOf(word)
        val end = text.indexOf(word) + word.length
        try {
            spannableString.setSpan(ForegroundColorSpan(color), start, end,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
            text = spannableString
        } catch (e: IndexOutOfBoundsException) {
         println("'$word' was not not found in TextView text")
    }
}

在将文本设置到TextView后,像这样使用它

private val blueberry by lazy { getColor(R.color.blueberry) }

textViewTip.setColouredSpan("Warning", blueberry)

非常感谢你,伙计,你让我的一天变得更美好 :* - Ahsan Syed
应该是 Kotlin 实现的最佳答案。 - Oleksandr Bodashko
惊人的实现 - Vishal kumar singhvi
你可以简化代码,写成:val end = start + word.length - CoolMind

11
String text = "I don't like Hasina.";
textView.setText(spannableString(text, 8, 14));

private SpannableString spannableString(String text, int start, int end) {
    SpannableString spannableString = new SpannableString(text);
    ColorStateList redColor = new ColorStateList(new int[][]{new int[]{}}, new int[]{0xffa10901});
    TextAppearanceSpan highlightSpan = new TextAppearanceSpan(null, Typeface.BOLD, -1, redColor, null);

    spannableString.setSpan(highlightSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    spannableString.setSpan(new BackgroundColorSpan(0xFFFCFF48), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    spannableString.setSpan(new RelativeSizeSpan(1.5f), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

    return spannableString;
}

输出:

在这里输入图片描述


(Note: 该段文字为格式要求,无需翻译)

8

通过传递字符串和颜色来设置文本的颜色:

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

通过调用以下代码在TextView / Button / EditText等控件中设置文本:

TextView:

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

获取带颜色的字符串:

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

在 TextView 上设置文字:

txtView.setText(Html.fromHtml(name));

完成


8

Textview Span

使用kotlin-ktx,您可以轻松实现它

        bindView?.oneTimePasswordTitle?.text = buildSpannedString {
        append("One Time Password ")
        inSpans(
            ForegroundColorSpan(ContextCompat.getColor(bindView?.oneTimePasswordTitle?.context!!,R.color.colorPrimaryText))
        ){
            append(" (As Registered Email)")
        }

    }

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