如何更改TextView的一部分颜色?

ata*_*oyh 89 android textview uitextview

text = text + CepVizyon.getPhoneCode() + "\n\n"
            + getText(R.string.currentversion) + CepVizyon.getLicenseText();
    activationText.setText(text);   
myTextView.setText(text);
Run Code Online (Sandbox Code Playgroud)

我想改变CepVizyon.getPhoneCode()字符串的颜色.我怎样才能做到这一点?

and*_*oot 154

Spannable更灵活:

String text2 = text + CepVizyon.getPhoneCode() + "\n\n"
            + getText(R.string.currentversion) + CepVizyon.getLicenseText();

Spannable spannable = new SpannableString(text2);

spannable.setSpan(new ForegroundColorSpan(Color.WHITE), text.length(), (text + CepVizyon.getPhoneCode()).length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

myTextView.setText(spannable, TextView.BufferType.SPANNABLE);
Run Code Online (Sandbox Code Playgroud)

  • 感谢您的回答!这更像iOS中的NSAttributedString :)为了更加灵活,用text2.indexOf(CepVizyon.getPhoneCode())替换text.lenght,这使您不知道字符串的第一部分。 (3认同)

Man*_*esh 66

myTextView.setText(Html.fromHtml(text + "<font color=white>" + CepVizyon.getPhoneCode() + "</font><br><br>"
            + getText(R.string.currentversion) + CepVizyon.getLicenseText()));
Run Code Online (Sandbox Code Playgroud)


Fon*_*nix 48

如果您有需要颜色的静态文本,可以通过strings文件添加它而不需要任何代码:

<string name="already_have_an_account">Already have an account? <font color='#01C6DB'>Login</font></string>
Run Code Online (Sandbox Code Playgroud)

然后

<TextView
    android:layout_width="wrap_content"
    android:layout_height="64dp"
    android:text="@string/already_have_an_account"/>
Run Code Online (Sandbox Code Playgroud)

结果

在此输入图像描述

不确定这个api版本是什么工作,但是到目前为止我测试的api 19都不起作用,所以可能只有一些最新的api版本支持这个

编辑:正如@hairraisin在评论中提到的,尝试使用fgcolor而不是color字体颜色,那么它应该适用于较低的api级别,但需要更多测试才能确定

  • 我已经在API 15和API 25上使用`<font fgcolor = ...`成功测试了(虽然我没有专门测试19) (3认同)
  • 这不是一个理想的解决方案,因为它将翻译与文本颜色混合在一起。 (3认同)

Joe*_*ouz 15

关于Maneesh的答案,这将有效,但您需要添加和转义color属性的引号.

myTextView.setText(Html.fromHtml(text + "<font color=\"#FFFFFF\">" + CepVizyon.getPhoneCode() + "</font><br><br>"
            + getText(R.string.currentversion) + CepVizyon.getLicenseText()));
Run Code Online (Sandbox Code Playgroud)


Dmi*_*nov 12

这是 Kotlin 中用于SpannableString更改字符串部分颜色的解决方案。

    val phoneCodeColor = ContextCompat.getColor(this, R.color.myColor)
    val text = SpannableStringBuilder()
        .color(phoneCodeColor) { append("${ CepVizyon.getPhoneCode() }") }
        .append("\n\n")
        .append(getString(R.string.currentversion))
        .append(${ CepVizyon.getLicenseText() })

    activationText.text = text
    myTextView.text = text
Run Code Online (Sandbox Code Playgroud)


Ale*_*ruz 9

使用通用 Kotlin 扩展函数,它看起来像这样:

/**
 * Change the color of a part of the text contained in this textView
 *
 * @param subStringToColorize has to already be set in the textView's text
 * @param colorResId
 */
fun TextView.colorize(subStringToColorize: String, @ColorRes colorResId: Int) {

  val spannable: Spannable = SpannableString(text)

  val startIndex = text.indexOf(subStringToColorize, startIndex = 0, ignoreCase = false)
  val endIndex = startIndex + subStringToColorize.length

  val color: Int = ContextCompat.getColor(context, colorResId)

  if (startIndex != -1) {
      spannable.setSpan(ForegroundColorSpan(color),
          startIndex,
          endIndex,
          Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
      setText(spannable, TextView.BufferType.SPANNABLE)
   }
}
Run Code Online (Sandbox Code Playgroud)


Joh*_*ada 8

这是一个colorize基于 andyboot 回答的函数:

 /**
 * Colorize a specific substring in a string for TextView. Use it like this: <pre>
 * textView.setText(
 *     Strings.colorized("The some words are black some are the default.","black", Color.BLACK),
 *     TextView.BufferType.SPANNABLE
 * );
 * </pre>
 * @param text Text that contains a substring to colorize
 * @param word The substring to colorize
 * @param argb The color
 * @return the Spannable for TextView's consumption
 */
public static Spannable colorized(final String text, final String word, final int argb) {
    final Spannable spannable = new SpannableString(text);
    int substringStart=0;
    int start;
    while((start=text.indexOf(word,substringStart))>=0){
        spannable.setSpan(
                new ForegroundColorSpan(argb),start,start+word.length(),
                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
        );
        substringStart = start+word.length();
    }
    return spannable;
}
Run Code Online (Sandbox Code Playgroud)


Roh*_*ngh 6

使用字符转义 + Html.fromHtml()

在此处输入图片说明

如何将字符串存储在字符串资源文件夹中

<string name="textFromRes">
    &lt;font color="#FF0000">This is colored in red &lt;/font> This is not
</string>
Run Code Online (Sandbox Code Playgroud)

如何在 TextView 中显示?

String text = this.getResources().getString(R.string.textFromRes);
htmlText.setText(Html.fromHtml(text));
Run Code Online (Sandbox Code Playgroud)

奖金:

输出中的字符串如下所示

<string name="textFromRes">
    &lt;font color="#FF0000">This is colored in red &lt;/font> This is not
    &lt;br /&gt;
    &lt;h1> This is h1 heading &lt;/h1>
    &lt;br /&gt;
    &lt;h3> This is h2 subheading&lt;/h3>
    &lt;br /&gt;
    &lt;b> This text is bold&lt;/b>
    &lt;br /&gt;
    &lt;i> This text is italic&lt;/i>
    &lt;br /&gt;
    Android users expect your app to look and behave in a way that is
    consistent with the platform. Not only should you follow material
    design guidelines for visual and navigation patterns,
    but you should also follow quality guidelines for compatibility,
    performance, security, and more.
    &lt;br /&gt;
    &lt;br /&gt;
    The following links provide everything you need to design a high quality Android app.
</string>
Run Code Online (Sandbox Code Playgroud)


Anh*_*Duy 5

这对我有好处!

            Spannable spannable = new SpannableString("ABC In-Network DEF");
            String str = spannable.toString();
            iStart = str.indexOf("In-Network");
            iEnd = iStart + 10;/*10 characters = in-network. */

            SpannableString ssText = new SpannableString(spannable);
            ClickableSpan clickableSpan = new ClickableSpan() {
                @Override
                public void onClick(View widget) {
                    //your code at here.
                }

                @Override
                public void updateDrawState(TextPaint ds) {
                    super.updateDrawState(ds);
                    ds.setUnderlineText(true);
                    ds.setColor(getResources().getColor(R.color.green));
                }
            };
            ssText.setSpan(clickableSpan, iStart, iEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            mTextView.setText(ssText);
            mTextView.setMovementMethod(LinkMovementMethod.getInstance());
            mTextView.setHighlightColor(Color.TRANSPARENT);
            mTextView.setEnabled(true);
Run Code Online (Sandbox Code Playgroud)


Exp*_*sam 5

我不喜欢每次我想要对文本的某些部分进行着色时都通过代码执行此操作的想法,我在所有应用程序中都做了很多事情(并且因为在某些情况下文本是在运行时使用不同的内联设置的)定义的颜色)所以我创建了自己的MarkableTextView.

我们的想法是:

  • 从字符串中检测 XML 标签
  • 识别并匹配标签名称
  • 提取并保存文本的属性和位置
  • 删除标签并保留内容
  • 迭代属性并应用样式

这是一步一步的过程:

首先,我需要一种在给定字符串中查找 XML 标签的方法,并且Regex成功了。

<([a-zA-Z]+(?:-[a-zA-Z0-9]+)*)(?:\s+([^>]*))?>([^>][^<]*)</\1\s*>
Run Code Online (Sandbox Code Playgroud)

为了使上述内容与 XML 标签相匹配,它必须满足以下条件:

  • 有效的标签名称 like<a> <a > <a-a> <a ..attrs..>但不是< a> <1>
  • 具有匹配名称<a></a>但不匹配的结束标记<a></b>
  • 任何内容,因为不需要设置“无”样式

现在对于属性我们将使用这个..

([a-zA-Z]+)\s*=\s*(['"])\s*([^'"]+?)\s*\2
Run Code Online (Sandbox Code Playgroud)

它具有相同的概念,通常我不需要为两者走得太远,因为如果有任何内容不符合格式,编译器将处理其余的事情。

现在我们需要一个可以保存提取数据的类:

public class MarkableSheet {

    private String attributes;
    private String content;
    private int outset;
    private int ending;
    private int offset;
    private int contentLength;

    public MarkableSheet(String attributes, String content, int outset, int ending, int offset, int contentLength) {

        this.attributes = attributes;
        this.content = content;
        this.outset = outset;
        this.ending = ending;
        this.offset = offset;
        this.contentLength = contentLength;
    }

    public String getAttributes() {
        return attributes;
    }

    public String getContent() {
        return content;
    }

    public int getOutset() {
        return outset;
    }

    public int getContentLength() {
        return contentLength;
    }

    public int getEnding() {
        return ending;
    }

    public int getOffset() {
        return offset;
    }
}
Run Code Online (Sandbox Code Playgroud)

首先,我们要添加这个很酷的迭代器,我已经使用它很长时间来循环匹配(不记得作者了)

public static Iterable<MatchResult> matches(final Pattern p, final CharSequence input) {

        return new Iterable<MatchResult>() {

            public Iterator<MatchResult> iterator() {

                return new Iterator<MatchResult>() {

                    // Use a matcher internally.
                    final Matcher matcher = p.matcher(input);

                    // Keep a match around that supports any interleaving of hasNext/next calls.
                    MatchResult pending;

                    public boolean hasNext() {

                        // Lazily fill pending, and avoid calling find() multiple times if the
                        // clients call hasNext() repeatedly before sampling via next().
                        if (pending == null && matcher.find()) {
                            pending = matcher.toMatchResult();
                        }
                        return pending != null;
                    }

                    public MatchResult next() {

                        // Fill pending if necessary (as when clients call next() without
                        // checking hasNext()), throw if not possible.
                        if (!hasNext()) { throw new NoSuchElementException(); }

                        // Consume pending so next call to hasNext() does a find().
                        MatchResult next = pending;
                        pending = null;

                        return next;
                    }

                    /** Required to satisfy the interface, but unsupported. */
                    public void remove() { throw new UnsupportedOperationException(); }
                };
            }
        };
    }
Run Code Online (Sandbox Code Playgroud)

可标记文本视图:

public class MarkableTextView extends AppCompatTextView {

    public MarkableTextView(Context context) {
        super(context);
    }

    public MarkableTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MarkableTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public void setText(CharSequence text, BufferType type) {

        // Intercept and process text
        text = prepareText(text.toString());

        super.setText(text, type);
    }

    public Spannable Markable;

    private Spannable prepareText(String text) {

        String parcel = text;
        Multimap<String, MarkableSheet> markableSheets = ArrayListMultimap.create();

        // Used to correct content position after tossing tags
        int totalOffset = 0;

        // Iterate through text
        for (MatchResult match : matches(Markable.Patterns.XML, parcel)) {

            // Get tag name
            String tag = match.group(1);

            // Match with a defined tag name "case-sensitive"
            if (!tag.equals(Markable.Tags.MARKABLE)) {

                // Break if no match
                break;
            }

            // Extract data
            String attributes = match.group(2);
            String content = match.group(3);

            int outset = match.start(0);
            int ending = match.end(0);
            int offset = totalOffset; // offset=0 since no preceded changes happened
            int contentLength = match.group(3).length();

            // Calculate offset for the next element
            totalOffset = (ending - outset) - contentLength;

            // Add to markable sheets
            MarkableSheet sheet =
                    new MarkableSheet(attributes, content, outset, ending, offset, contentLength);
            markableSheets.put(tag, sheet);

            // Toss the tag and keep content
            Matcher reMatcher = Markable.Patterns.XML.matcher(parcel);
            parcel = reMatcher.replaceFirst(content);
        }

        // Initialize spannable with the modified text
        Markable = new SpannableString(parcel);

        // Iterate through markable sheets
        for (MarkableSheet sheet : markableSheets.values()) {

            // Iterate through attributes
            for (MatchResult match : matches(Markable.Patterns.ATTRIBUTES, sheet.getAttributes())) {

                String attribute = match.group(1);
                String value = match.group(3);

                // Apply styles
                stylate(attribute,
                        value,
                        sheet.getOutset(),
                        sheet.getOffset(),
                        sheet.getContentLength());
            }
        }

        return Markable;
    }
Run Code Online (Sandbox Code Playgroud)

最后,样式,所以这是我为此答案制作的一个非常简单的样式器:

public void stylate(String attribute, String value, int outset, int offset, int length) {

        // Correct position
        outset -= offset;
        length += outset;

        if (attribute.equals(Markable.Tags.TEXT_STYLE)) {

            if (value.contains(Markable.Tags.BOLD) && value.contains(Markable.Tags.ITALIC)) {

                Markable.setSpan(
                        new StyleSpan(Typeface.BOLD_ITALIC),
                        outset,
                        length,
                        Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
            else if (value.contains(Markable.Tags.BOLD)) {

                Markable.setSpan(
                        new StyleSpan(Typeface.BOLD),
                        outset,
                        length,
                        Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            }

            else if (value.contains(Markable.Tags.ITALIC)) {

                Markable.setSpan(
                        new StyleSpan(Typeface.ITALIC),
                        outset,
                        length,
                        Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            }

            if (value.contains(Markable.Tags.UNDERLINE)) {

                Markable.setSpan(
                        new UnderlineSpan(),
                        outset,
                        length,
                        Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
        }

        if (attribute.equals(Markable.Tags.TEXT_COLOR)) {

            if (value.equals(Markable.Tags.ATTENTION)) {

                Markable.setSpan(
                        new ForegroundColorSpan(ContextCompat.getColor(
                                getContext(),
                                R.color.colorAttention)),
                        outset,
                        length,
                        Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
            else if (value.equals(Markable.Tags.INTERACTION)) {

                Markable.setSpan(
                        new ForegroundColorSpan(ContextCompat.getColor(
                                getContext(),
                                R.color.colorInteraction)),
                        outset,
                        length,
                        Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

Markable包含定义的类如下所示:

public class Markable {

    public static class Patterns {

        public static final Pattern XML =
                Pattern.compile("<([a-zA-Z]+(?:-[a-zA-Z0-9]+)*)(?:\\s+([^>]*))?>([^>][^<]*)</\\1\\s*>");
        public static final Pattern ATTRIBUTES =
                Pattern.compile("(\\S+)\\s*=\\s*(['\"])\\s*(.+?)\\s*\\2");
    }

    public static class Tags {

        public static final String MARKABLE = "markable";

        public static final String TEXT_STYLE = "textStyle";
        public static final String BOLD = "bold";
        public static final String ITALIC = "italic";
        public static final String UNDERLINE = "underline";

        public static final String TEXT_COLOR = "textColor";
        public static final String ATTENTION = "attention";
        public static final String INTERACTION = "interaction";
    }
}
Run Code Online (Sandbox Code Playgroud)

我们现在需要的只是引用一个字符串,基本上它应该如下所示:

<string name="markable_string">
    <![CDATA[Hello <markable textStyle=\"underline\" textColor=\"interaction\">world</markable>!]]>
</string>
Run Code Online (Sandbox Code Playgroud)

确保用 a 包裹标签并用CDATA Section转义。"\

我将其作为一个模块化解决方案,以各种不同的方式处理文本的各个部分,而不需要在后面填充不必要的代码。


Tin*_*825 5

我按照安迪·布特所说的做了,但我也有一个可点击的跨度,但它不起作用,因为setSpans调用了顺序。所以你必须先调用spannable.setSpan(clickableSpanand...thenspannable.setSpan(new ForegroundColorSpan...来获取 TextView 中的颜色


Gas*_*lén 5

我做了这个小功能,只需将您的文本传递给颜色,您想要为该文本着色的开始和结束索引以及颜色本身

科特林

   private fun colorMyText(inputText:String,startIndex:Int,endIndex:Int,textColor:Int):Spannable{
            val outPutColoredText: Spannable = SpannableString(inputText)
            outPutColoredText.setSpan(
                ForegroundColorSpan(textColor), startIndex, endIndex,
                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
            )
            return outPutColoredText
        }
Run Code Online (Sandbox Code Playgroud)

用法

txt_comment.text = colorMyText("Comentario: ${item.comentario}",0,13,Color.BLACK)
Run Code Online (Sandbox Code Playgroud)


小智 5

受到上面Alejandro H. Cruz 的回答的启发。

他的函数仅适用于单个子字符串匹配,我已经更新了他的方法以使用正则表达式,并且应该更新所有匹配的颜色:

fun TextView.colorizeAll(subStringToColorize: String, @ColorRes colorResId: Int) {

    val color: Int = ContextCompat.getColor(context, colorResId)

    val spannable: Spannable = SpannableString(text)

    val pattern = subStringToColorize.toRegex()

    val matches = pattern.findAll(text, 0)

    matches.forEach { match ->

        val startIndex = match.range.first

        val endIndex = match.range.last + match.range.step

        spannable.setSpan(ForegroundColorSpan(color),
                startIndex,
                endIndex,
                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
        setText(spannable, TextView.BufferType.SPANNABLE)

    }
}
Run Code Online (Sandbox Code Playgroud)


KBo*_*Bog 5

我创建了这个小助手方法,可以从以下位置调用TextView

fun TextView.attributedString(
    forText: String,
    foregroundColor: Int? = null,
    style: StyleSpan? = null
) {
  val spannable: Spannable = SpannableString(text)

  // check if the text we're highlighting is empty to abort
  if (forText.isEmpty()) {
    return
  }

  // compute the start and end indices from the text
  val startIdx = text.indexOf(forText)
  val endIdx = startIdx + forText.length

  // if the indices are out of bounds, abort as well
  if (startIdx < 0 || endIdx > text.length) {
    return
  }

  // check if we can apply the foreground color
  foregroundColor?.let {
    spannable.setSpan(
        ForegroundColorSpan(it),
        startIdx,
        endIdx,
        Spannable.SPAN_INCLUSIVE_EXCLUSIVE
    )
  }

  // check if we have a stylespan
  style?.let {
    spannable.setSpan(
        style,
        startIdx,
        endIdx,
        Spannable.SPAN_INCLUSIVE_EXCLUSIVE
    )
  }

  // apply it
  text = spannable
}
Run Code Online (Sandbox Code Playgroud)

使用方法:

plateText.text = "Hello world!"

// This will color the part "world" to whatever color you have defined
// And make the word **bold**.
plateText.attributedString(
   "world",
   getColor(R.color.colorMatchingText, null),
   StyleSpan(Typeface.BOLD)
)
Run Code Online (Sandbox Code Playgroud)

在 API 29 上测试,干杯!