Comment puis-je changer la couleur d’une partie d’un TextView?

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

Je veux changer la couleur de la CepVizyon.getPhoneCode() de CepVizyon.getPhoneCode() . Comment puis-je faire ceci?

Spannable est plus flexible:

 Ssortingng text2 = text + CepVizyon.getPhoneCode() + "\n\n" + getText(R.ssortingng.currentversion) + CepVizyon.getLicenseText(); Spannable spannable = new SpannableSsortingng(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 + "" + CepVizyon.getPhoneCode() + "

" + getText(R.ssortingng.currentversion) + CepVizyon.getLicenseText()));

Si vous avez du texte statique qui nécessite de la couleur, vous pouvez l’append sans code via le fichier de chaînes:

 Already have an account? Login 

puis

  

résultat

entrer la description de l'image ici

Je ne sais pas sur quelles versions d’API cela fonctionne, mais ça ne marche pas pour api 19 qui a été testé jusqu’ici, donc probablement seulement certaines des versions d’API les plus récentes supportent cela.

edit: comme @hairraisin mentionné dans les commentaires, essayez d’utiliser fgcolor au lieu de color pour la color de la police, alors cela devrait fonctionner pour les niveaux d’api inférieurs, mais il faut plus de tests pour être sûr

En ce qui concerne la réponse de Maneesh, cela fonctionnera mais vous devez append et échapper les guillemets pour l’atsortingbut de couleur.

 myTextView.setText(Html.fromHtml(text + "" + CepVizyon.getPhoneCode() + "

" + getText(R.ssortingng.currentversion) + CepVizyon.getLicenseText()));

C’est bon pour moi!

  Spannable spannable = new SpannableSsortingng("ABC In-Network DEF"); Ssortingng str = spannable.toSsortingng(); iStart = str.indexOf("In-Network"); iEnd = iStart + 10;/*10 characters = in-network. */ SpannableSsortingng ssText = new SpannableSsortingng(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); 

Voici une fonction de colorize basée sur la réponse d’andboot:

  /** * Colorize a specific subssortingng in a ssortingng for TextView. Use it like this: 
 * textView.setText( * Ssortingngs.colorized("The some words are black some are the default.","black", Color.BLACK), * TextView.BufferType.SPANNABLE * ); * 

* @param text Text that contains a subssortingng to colorize * @param word The subssortingng to colorize * @param argb The color * @return the Spannable for TextView's consumption */ public static Spannable colorized(final Ssortingng text, final Ssortingng word, final int argb) { final Spannable spannable = new SpannableSsortingng(text); int subssortingngStart=0; int start; while((start=text.indexOf(word,subssortingngStart))>=0){ spannable.setSpan( new ForegroundColorSpan(argb),start,start+word.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE ); subssortingngStart = start+word.length(); } return spannable; }

Je n’aimais pas l’idée de le faire par code à chaque fois que je voulais colorer des parties du texte que je faisais beaucoup dans toutes mes applications (et dans certains cas, du texte est en cours d’exécution avec couleurs définies) donc j’ai créé mon propre MarkableTextView .

L’idée était de:

  • Détecter les balises XML de la chaîne
  • Identifier et faire correspondre le nom de la balise
  • Extraire et enregistrer les atsortingbuts et la position du texte
  • Supprimer la balise et conserver le contenu
  • Itérer à travers les atsortingbuts et appliquer des styles

Voici le processus étape par étape:

D’abord, j’avais besoin d’un moyen de trouver des balises XML dans une chaîne donnée et Regex fait l’affaire.

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

Pour que ce qui précède corresponde à une balise XML, il doit répondre aux critères suivants:

  • Nom de tag valide tel que mais pas <1>
  • Fermeture de la balise dont le nom correspond à mais pas à
  • Tout contenu, puisqu’il n’y a pas besoin de styler “rien”

Maintenant, pour les atsortingbuts, nous allons utiliser celui-ci ..

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

Il a le même concept et généralement je n’ai pas eu besoin d’aller loin pour les deux, car le compilateur s’occupera du rest si quelque chose sort du format.

Maintenant, nous avons besoin d’une classe pouvant contenir les données extraites:

 public class MarkableSheet { private Ssortingng atsortingbutes; private Ssortingng content; private int outset; private int ending; private int offset; private int contentLength; public MarkableSheet(Ssortingng atsortingbutes, Ssortingng content, int outset, int ending, int offset, int contentLength) { this.atsortingbutes = atsortingbutes; this.content = content; this.outset = outset; this.ending = ending; this.offset = offset; this.contentLength = contentLength; } public Ssortingng getAtsortingbutes() { return atsortingbutes; } public Ssortingng getContent() { return content; } public int getOutset() { return outset; } public int getContentLength() { return contentLength; } public int getEnding() { return ending; } public int getOffset() { return offset; } } 

Avant toute chose, nous allons append ce cool iterator que j’utilise depuis longtemps pour parcourir les correspondances ( je ne me souviens plus de l’auteur) :

 public static Iterable matches(final Pattern p, final CharSequence input) { return new Iterable() { public Iterator iterator() { return new Iterator() { // 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, AtsortingbuteSet attrs) { super(context, attrs); } public MarkableTextView(Context context, AtsortingbuteSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public void setText(CharSequence text, BufferType type) { // Intercept and process text text = prepareText(text.toSsortingng()); super.setText(text, type); } public Spannable Markable; private Spannable prepareText(Ssortingng text) { Ssortingng parcel = text; Multimap 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 Ssortingng 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 Ssortingng atsortingbutes = match.group(2); Ssortingng 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(atsortingbutes, 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 SpannableSsortingng(parcel); // Iterate through markable sheets for (MarkableSheet sheet : markableSheets.values()) { // Iterate through atsortingbutes for (MatchResult match : matches(Markable.Patterns.ATTRIBUTES, sheet.getAtsortingbutes())) { Ssortingng atsortingbute = match.group(1); Ssortingng value = match.group(3); // Apply styles stylate(atsortingbute, value, sheet.getOutset(), sheet.getOffset(), sheet.getContentLength()); } } return Markable; } 

Enfin, voici un styler très simple que j’ai créé pour cette réponse:

 public void stylate(Ssortingng atsortingbute, Ssortingng value, int outset, int offset, int length) { // Correct position outset -= offset; length += outset; if (atsortingbute.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 (atsortingbute.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); } } } 

Et voici à quoi Markable classe Markable contenant les définitions:

 public class Markable { public static class Patterns { public static final Pattern XML = Pattern.comstack("<([a-zA-Z]+(?:-[a-zA-Z0-9]+)*)(?:\\s+([^>]*))?>([^>][^<]*)"); public static final Pattern ATTRIBUTES = Pattern.comstack("(\\S+)\\s*=\\s*(['\"])\\s*(.+?)\\s*\\2"); } public static class Tags { public static final Ssortingng MARKABLE = "markable"; public static final Ssortingng TEXT_STYLE = "textStyle"; public static final Ssortingng BOLD = "bold"; public static final Ssortingng ITALIC = "italic"; public static final Ssortingng UNDERLINE = "underline"; public static final Ssortingng TEXT_COLOR = "textColor"; public static final Ssortingng ATTENTION = "attention"; public static final Ssortingng INTERACTION = "interaction"; } } 

Tout ce dont nous avons besoin maintenant est de faire référence à une chaîne et, en gros, elle devrait ressembler à ceci:

  world!]]>  

Veillez à envelopper les balises avec une CDATA Section et à échapper " avec \ .

Je l’ai conçu comme une solution modulaire pour traiter des parties du texte de différentes manières sans avoir besoin de mettre du code inutile.

J’ai fait comme Andy Boot a dit, mais j’ai eu une période cliquable aussi, et cela n’a pas fonctionné parce que l’ordre des setSpans ont été appelés. Vous devez donc d’abord appeler spannable.setSpan(clickableSpanand... puis spannable.setSpan(new ForegroundColorSpan... pour obtenir la couleur dans TextView).

L’une des méthodes consiste à diviser myTextView en quelques TextViews distinctes, dont l’une serait uniquement destinée au code téléphonique. Ensuite, le contrôle de la couleur de ce TextView spécifique est assez simple.