TextViewの一部の色を変更するにはどうすればよいですか?


102
text = text + CepVizyon.getPhoneCode() + "\n\n"
            + getText(R.string.currentversion) + CepVizyon.getLicenseText();
    activationText.setText(text);   
myTextView.setText(text);

CepVizyon.getPhoneCode()の文字列の色を変更したい。これどうやってするの?




その質問は、あなたの質問の約3か月前の10月19日16:27に行われました。ただし、重複するターゲットにする必要があるのは、常に最も古い投稿であるとは限りません。表示回数、投票数、回答数、質問の明確性を考慮に入れる必要があります。これを重複としてマークすることで、質問に回答する他の回答を見つけるのに役立ちます。
Suragch 2017


本当に舞台裏で何を理解するために、私はいつもこのような綿密な記事を読むことをお勧め:medium.com/androiddevelopers/...は
ミハルVician

回答:


169

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

3
この回答ありがとうございます!これはiOSのNSAttributedStringに似ています:)さらに柔軟にするには、text.lenghtをtext2.indexOf(CepVizyon.getPhoneCode())に置き換えます。これにより、文字列の最初の部分がわからなくなります。
iGranDav

1
あなたは置く必要があります()text.lengthようlengthな方法ではない分野です。私はそれを自分で行いますが、編集は少なくとも6文字でなければなりません:)
MSX

これは最善の答えです。
ポーアーランディスマルチネス2016

1
Spannableの問題は、ellipsize = endが機能しないことです。これは、場合によってはかなり深刻な問題です。
ファンカルロスオスピナゴンザレス

1
うまく動作します。ただし、HTML文字列を作成することをお勧めします。そして、それをHTMLクラスを介して解析します。Html.fromHtml(R.id.your_html_string);
sud007 2017年

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

60

色が必要な静的テキストがある場合は、文字列ファイルを介してコードなしで追加できます。

<string name="already_have_an_account">Already have an account? <font color='#01C6DB'>Login</font></string>

その後

<TextView
    android:layout_width="wrap_content"
    android:layout_height="64dp"
    android:text="@string/already_have_an_account"/>

結果

ここに画像の説明を入力してください

これが機能するAPIバージョンはわかりませんが、これまでにテストされたAPI 19では機能しないため、おそらく最新のAPIバージョンの一部のみがこれをサポートしています。

編集:@hairraisinがコメントで言及されているように、フォントの色ではfgcolorなくを使用してみてくださいcolor、それはより低いAPIレベルで機能するはずですが、確認するためにさらにテストが必要です


3
私は<font fgcolor=...API 15とAPI 25 を使用してテストに成功しました(ただし、特に19はテストしていません)
ヘアレーズン2018

プログラムでテキストを設定すると機能しません。:(
Rohit Singh

翻訳とテキストの色が混在するため、これは理想的なソリューションではありません。
ミロシュČernilovský

15

Maneeshの回答に関しては、これは機能しますが、color属性の引用符を追加してエスケープする必要があります。

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

7

いいですよ!

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

5

SpannableString文字列の一部の色を変更するために使用するKotlinのソリューション。

    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

1
ありがとうございました。Kotlinのための単にエレガントなソリューション。
Nhon Nguyen

4

以下は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;
}

3

私がすべてのアプリで頻繁に行っているテキストの一部に色を付けたいときはいつでもコードでこれを行うという考えが好きではありませんでした定義された色)私は自分で作成しましたMarkableTextView

アイデアは:

  • 文字列からXMLタグを検出する
  • タグ名を特定して一致させる
  • テキストの属性と位置を抽出して保存する
  • タグを削除してコンテンツを保持する
  • 属性を反復処理してスタイルを適用する

プロセスは次のとおりです。

最初に、特定の文字列でXMLタグを検索する方法が必要でしたRegex

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

上記がXMLタグと一致するには、次の基準が必要です。

  • 以下のような有効なタグ名<a> <a > <a-a> <a ..attrs..>ではなく、< a> <1>
  • 次のように一致する名前を持つが、では<a></a>ない終了タグ<a></b>
  • 「何も」のスタイルを設定する必要がないため、任意のコンテンツ

次に、属性にこれを使用します。

([a-zA-Z]+)\s*=\s*(['"])\s*([^'"]+?)\s*\2

それは同じ概念を持っています、そして、何かがフォーマットから出た場合、コンパイラが残りを処理するので、一般的に私は両方のために遠くに行く必要はありませんでした。

次に、抽出されたデータを保持できるクラスが必要です。

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

何よりもまず、マッチをループするために長い間使用してきたこのクールなイテレータを追加します(作成者を思い出せません)

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

MarkableTextView:

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

最後に、スタイリング、それで私がこの答えのために作った非常にシンプルなスタイラーです:

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

そして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";
    }
}

今必要なのは文字列を参照することだけで、基本的には次のようになります。

<string name="markable_string">
    <![CDATA[Hello <markable textStyle=\"underline\" textColor=\"interaction\">world</markable>!]]>
</string>

タグは必ずa CDATA Sectionで囲み、でエスケープ"してください\

私は、不要なコードを背後に詰め込む必要なしに、テキストの一部をさまざまな方法で処理するためのモジュラーソリューションとしてこれを作成しました。


3

アンディブートが言ったように私はやったが、クリック可能なスパンもあり、注文setSpansが呼び出されたために機能しなかった。あなたが最初の呼び出しに持っているのでspannable.setSpan(clickableSpanand...、その後spannable.setSpan(new ForegroundColorSpan...のTextView内の色を取得します


2

私はこの小さな関数を作成しました。テキストに色を渡し、そのテキストの色にしたいものの開始インデックスと終了インデックス、および色自体を渡します

コトリン

   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
        }

使用法

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

1

文字エスケープ+ Html.fromHtml()を使用する

ここに画像の説明を入力してください

文字列を文字列リソースフォルダに格納する方法

<string name="textFromRes">
    &lt;font color="#FF0000">This is colored in red &lt;/font> This is not
</string>

TextViewで表示する方法?

String text = this.getResources().getString(R.string.textFromRes);
htmlText.setText(Html.fromHtml(text));

ボーナス:

出力の文字列は次のようになります

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

1

汎用の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 = if (/* Your code for isMarshmallowOrUp() */ ) {
      this.context.getColor(colorResId)
  } else {
      this.context.resources.getColor(colorResId)
  }

  spannable.setSpan(ForegroundColorSpan(color),
                  startIndex,
                  endIndex,
                  Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)

  this.setText(spannable, TextView.BufferType.SPANNABLE)
}

-5

1つの方法は、myTextViewいくつかに分割するTextViewsことです。そのうちの1つは電話コード専用です。次に、この特定の色を制御することTextViewは非常に簡単です。


7
いや、お尻の痛み。スパナブルを使用するのが正しい方法です。
Marc DiMillo、2016

Spannableクラスは分割せずにそれを行うことができます
Sz-Nika Janos
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.