Changer la couleur du texte d’un seul ClickableSpan lorsqu’il est pressé sans affecter les autres ClickableSpans dans le même TextView

J’ai un TextView avec plusieurs ClickableSpans. Lorsqu’on appuie sur ClickableSpan, je souhaite qu’il change la couleur de son texte.

J’ai essayé de définir une liste d’états de couleurs en tant qu’atsortingbut textColorLink du TextView. Cela n’aboutit pas au résultat souhaité car cela entraîne la modification de la couleur de toutes les plages lorsque l’utilisateur clique n’importe où sur TextView.

Il est intéressant de noter que l’utilisation de textColorHighlight pour modifier la couleur d’arrière-plan fonctionne comme suit: Cliquer sur une plage modifie uniquement la couleur d’arrière-plan de cette plage et cliquer n’importe où ailleurs dans TextView ne fait rien.

J’ai également essayé de définir ForegroundColorSpans avec les mêmes limites que les ClickableSpans, où je passe la même liste d’états de couleurs que la couleur ci-dessus. Cela ne fonctionne pas non plus. Les intervalles conservent toujours la couleur de l’état par défaut dans la liste d’état des couleurs et n’entrent jamais dans l’état pressé.

Est-ce que quelqu’un sait comment faire ça?

Voici la liste des états de couleurs que j’ai utilisée:

    

J’ai finalement trouvé une solution qui fait tout ce que je voulais. C’est basé sur cette réponse .

Ceci est ma méthode LinkMovementMethod modifiée qui marque une plage comme pressée au début d’un événement tactile (MotionEvent.ACTION_DOWN) et la désélectionne lorsque la touche se termine ou lorsque la zone tactile se déplace hors de la plage.

 public class LinkTouchMovementMethod extends LinkMovementMethod { private TouchableSpan mPressedSpan; @Override public boolean onTouchEvent(TextView textView, Spannable spannable, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { mPressedSpan = getPressedSpan(textView, spannable, event); if (mPressedSpan != null) { mPressedSpan.setPressed(true); Selection.setSelection(spannable, spannable.getSpanStart(mPressedSpan), spannable.getSpanEnd(mPressedSpan)); } } else if (event.getAction() == MotionEvent.ACTION_MOVE) { TouchableSpan touchedSpan = getPressedSpan(textView, spannable, event); if (mPressedSpan != null && touchedSpan != mPressedSpan) { mPressedSpan.setPressed(false); mPressedSpan = null; Selection.removeSelection(spannable); } } else { if (mPressedSpan != null) { mPressedSpan.setPressed(false); super.onTouchEvent(textView, spannable, event); } mPressedSpan = null; Selection.removeSelection(spannable); } return true; } private TouchableSpan getPressedSpan( TextView textView, Spannable spannable, MotionEvent event) { int x = (int) event.getX() - textView.getTotalPaddingLeft() + textView.getScrollX(); int y = (int) event.getY() - textView.getTotalPaddingTop() + textView.getScrollY(); Layout layout = textView.getLayout(); int position = layout.getOffsetForHorizontal(layout.getLineForVertical(y), x); TouchableSpan[] link = spannable.getSpans(position, position, TouchableSpan.class); TouchableSpan touchedSpan = null; if (link.length > 0 && positionWithinTag(position, spannable, link[0])) { touchedSpan = link[0]; } return touchedSpan; } private boolean positionWithinTag(int position, Spannable spannable, Object tag) { return position >= spannable.getSpanStart(tag) && position <= spannable.getSpanEnd(tag); } } 

Cela doit être appliqué à TextView comme ceci:

  yourTextView.setMovementMethod(new LinkTouchMovementMethod()); 

Et c'est le ClickableSpan modifié qui modifie l'état de dessin en fonction de l'état pressé défini par le LinkTouchMovementMethod: (il supprime également le soulignement des liens)

 public abstract class TouchableSpan extends ClickableSpan { private boolean mIsPressed; private int mPressedBackgroundColor; private int mNormalTextColor; private int mPressedTextColor; public TouchableSpan(int normalTextColor, int pressedTextColor, int pressedBackgroundColor) { mNormalTextColor = normalTextColor; mPressedTextColor = pressedTextColor; mPressedBackgroundColor = pressedBackgroundColor; } public void setPressed(boolean isSelected) { mIsPressed = isSelected; } @Override public void updateDrawState(TextPaint ds) { super.updateDrawState(ds); ds.setColor(mIsPressed ? mPressedTextColor : mNormalTextColor); ds.bgColor = mIsPressed ? mPressedBackgroundColor : 0xffeeeeee; ds.setUnderlineText(false); } } 

Solution beaucoup plus simple, IMO:

 final int colorForThisClickableSpan = Color.RED; //Set your own conditional logic here. final ClickableSpan link = new ClickableSpan() { @Override public void onClick(final View view) { //Do something here! } @Override public void updateDrawState(TextPaint ds) { super.updateDrawState(ds); ds.setColor(colorForThisClickableSpan); } }; 

La réponse de legr3c m’a beaucoup aidé. Et j’aimerais append quelques remarques.

Remarque n ° 1.

 TextView myTextView = (TextView) findViewById(R.id.my_textview); myTextView.setMovementMethod(new LinkTouchMovementMethod()); myTextView.setHighlightColor(getResources().getColor(android.R.color.transparent)); SpannableSsortingng mySpannable = new SpannableSsortingng(text); mySpannable.setSpan(new TouchableSpan(), 0, 7, 0); mySpannable.setSpan(new TouchableSpan(), 15, 18, 0); myTextView.setText(mySpannable, BufferType.SPANNABLE); 

J’ai appliqué LinkTouchMovementMethod à un TextView avec deux plages. Les scopes étaient surlignées en bleu lorsque vous les cliquiez. myTextView.setHighlightColor(getResources().getColor(android.R.color.transparent)); Correction du bug.

Remarque n ° 2.

N’oubliez pas de récupérer les couleurs des ressources lors de la transmission de normalTextColor , pressedTextColor et pressedBackgroundColor .

Doit passer la couleur résolue au lieu de l’ID de la ressource ici

Toutes ces solutions sont trop de travail.

Il suffit de définir android:textColorLink dans votre TextView à un sélecteur. Ensuite, créez un clickableSpan sans avoir besoin de remplacer updateDrawState (…). Terminé.

voici un exemple rapide:

Dans votre ssortingngs.xml avoir une chaîne déclarée comme ceci:

 This is my message%1$s these words are highlighted%2$s and awesome.  

alors dans votre activité:

 private void createMySpan(){ final Ssortingng token = "#"; Ssortingng mySsortingng = getSsortingng(R.ssortingng.myssortingng,token,token); int start = mySsortingng.toSsortingng().indexOf(token); //we do -1 since we are about to remove the tokens afterwards so it shifts int finish = mySsortingng.toSsortingng().indexOf(token, start+1)-1; mySsortingng = mySsortingng.replaceAll(token, ""); //create your spannable final SpannableSsortingng spannable = new SpannableSsortingng(mySsortingng); final ClickableSpan clickableSpan = new ClickableSpan() { @Override public void onClick(final View view) { doSomethingOnClick(); } }; spannable.setSpan(clickableSpan, start, finish, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); mTextView.setMovementMethod(LinkMovementMethod.getInstance()); mTextView.setText(spannable); } 

et heres les parties importantes ..déclare un sélecteur comme celui-ci l’appelle myselector.xml :

      

Et enfin dans votre TextView dans XML, faites ceci:

   

Maintenant, vous pouvez avoir un état pressé sur votre clickableSpan.

essayez cette ClickableSpan personnalisée:

 class MyClickableSpan extends ClickableSpan { private Ssortingng action; private int fg; private int bg; private boolean selected; public MyClickableSpan(Ssortingng action, int fg, int bg) { this.action = action; this.fg = fg; this.bg = bg; } @Override public void onClick(View widget) { Log.d(TAG, "onClick " + action); } @Override public void updateDrawState(TextPaint ds) { ds.linkColor = selected? fg : 0xffeeeeee; super.updateDrawState(ds); } } 

et ce SpanWatcher:

 class Watcher implements SpanWatcher { private TextView tv; private MyClickableSpan selectedSpan = null; public Watcher(TextView tv) { this.tv = tv; } private void changeColor(Spannable text, Object what, int start, int end) { // Log.d(TAG, "changeFgColor " + what); if (what == Selection.SELECTION_END) { MyClickableSpan[] spans = text.getSpans(start, end, MyClickableSpan.class); if (spans != null) { tv.setHighlightColor(spans[0].bg); if (selectedSpan != null) { selectedSpan.selected = false; } selectedSpan = spans[0]; selectedSpan.selected = true; } } } @Override public void onSpanAdded(Spannable text, Object what, int start, int end) { changeColor(text, what, start, end); } @Override public void onSpanChanged(Spannable text, Object what, int ostart, int oend, int nstart, int nend) { changeColor(text, what, nstart, nend); } @Override public void onSpanRemoved(Spannable text, Object what, int start, int end) { } } 

testez-le dans onCreate:

  TextView tv = new TextView(this); tv.setTextSize(40); tv.setMovementMethod(LinkMovementMethod.getInstance()); SpannableSsortingngBuilder b = new SpannableSsortingngBuilder(); b.setSpan(new Watcher(tv), 0, 0, Spanned.SPAN_INCLUSIVE_INCLUSIVE); b.append("this is "); int start = b.length(); MyClickableSpan link = new MyClickableSpan("link0 action", 0xffff0000, 0x88ff0000); b.append("link 0"); b.setSpan(link, start, b.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); b.append("\nthis is "); start = b.length(); b.append("link 1"); link = new MyClickableSpan("link1 action", 0xff00ff00, 0x8800ff00); b.setSpan(link, start, b.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); b.append("\nthis is "); start = b.length(); b.append("link 2"); link = new MyClickableSpan("link2 action", 0xff0000ff, 0x880000ff); b.setSpan(link, start, b.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); tv.setText(b); setContentView(tv); 

Ceci est ma solution si vous avez beaucoup d’éléments de clic (nous avons besoin d’une interface): L’interface:

 public interface IClickSpannableListener{ void onClickSpannText(Ssortingng text,int starts,int ends); } 

La classe qui gère l’événement:

 public class SpecialClickableSpan extends ClickableSpan{ private IClickSpannableListener listener; private Ssortingng text; private int starts, ends; public SpecialClickableSpan(Ssortingng text,IClickSpannableListener who,int starts, int ends){ super(); this.text = text; this.starts=starts; this.ends=ends; listener = who; } @Override public void onClick(View widget) { listener.onClickSpannText(text,starts,ends); } } 

En classe principale:

 class Main extends Activity implements IClickSpannableListener{ //Global SpannableSsortingng _spannableSsortingng; Object _backGroundColorSpan=new BackgroundColorSpan(Color.BLUE); private void setTextViewSpannable(){ _spannableSsortingng= new SpannableSsortingng("You can click «here» or click «in this position»"); _spannableSsortingng.setSpan(new SpecialClickableSpan("here",this,15,18),15,19, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); _spannableSsortingng.setSpan(new SpecialClickableSpan("in this position",this,70,86),70,86, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); TextView tv = (TextView)findViewBy(R.id.textView1); tv.setMovementMethod(LinkMovementMethod.getInstance()); tv.setText(spannableSsortingng); } @Override public void onClickSpannText(Ssortingng text, int inicio, int fin) { System.out.println("click on "+ text); _spannableSsortingng.removeSpan(_backGroundColorSpan); _spannableSsortingng.setSpan(_backGroundColorSpan, inicio, fin, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); ((TextView)findViewById(R.id.textView1)).setText(_spannableSsortingng); } } 

Placez le code Java comme ci-dessous:

 package com.synamegames.orbs; import android.view.MotionEvent; import android.view.View; import android.widget.TextView; public class CustomTouchListener implements View.OnTouchListener { public boolean onTouch(View view, MotionEvent motionEvent) { switch(motionEvent.getAction()){ case MotionEvent.ACTION_DOWN: ((TextView) view).setTextColor(0x4F4F4F); break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: ((TextView) view).setTextColor(0xCDCDCD); break; } return false; } } 

Dans le code ci-dessus, spécifiez la couleur de votre choix.

Changez le style .xml comme vous le souhaitez.

    

Essayez et dites que c’est ce que vous voulez ou autre chose. met-moi à jour mec