_text = text + CepVizyon.getPhoneCode() + "\n\n"
+ getText(R.string.currentversion) + CepVizyon.getLicenseText();
activationText.setText(text);
myTextView.setText(text);
_
CepVizyon.getPhoneCode()
の文字列の色を変更したい。これどうやってするの?
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);
myTextView.setText(Html.fromHtml(text + "<font color=white>" + CepVizyon.getPhoneCode() + "</font><br><br>"
+ getText(R.string.currentversion) + CepVizyon.getLicenseText()));
色が必要な静的テキストがある場合は、stringsファイルを介してコードなしで追加できます。
<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レベルで動作するはずですが、確認するためにさらにテストが必要です
Maneeshの回答に関しては、これは機能しますが、color属性の引用符を追加およびエスケープする必要があります。
myTextView.setText(Html.fromHtml(text + "<font color=\"#FFFFFF\">" + CepVizyon.getPhoneCode() + "</font><br><br>"
+ getText(R.string.currentversion) + CepVizyon.getLicenseText()));
それは私にとって良いことです!
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);
私はすべてのアプリでたくさん行っているテキストの一部を色付けするたびにコードでこれを行うという考えが好きではありませんでした(そして場合によってはテキストがランタイムで異なるインラインで設定されているため、定義された色)ので、私は自分のMarkableTextView
を作成しました。
アイデアは:
ステップバイステップのプロセス:
最初に、指定された文字列で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>
必ずCDATA Section
でタグをラップし、"
で\
をエスケープしてください。
これは、不要なコードを詰め込むことなく、さまざまな方法でテキストの一部を処理するモジュール式ソリューションとして作成しました。
Andybootの答えに基づいたcolorize
関数は次のとおりです。
/**
* 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;
}
私はアンディブートが言ったようにしたが、クリック可能なスパンもあり、setSpans
の順序が呼び出されたため、機能しませんでした。したがって、まずspannable.setSpan(clickableSpanand...
を呼び出してからspannable.setSpan(new ForegroundColorSpan...
を呼び出して、TextViewの色を取得する必要があります