9

I am using this code to remove formatting of a spannable text from start till end. The problem is that it is working successfully, but the last character in the text is still bold (or italics/underline).

removeSpan is not working on the last character in the text:

int startSelection = 0;
int endSelection = text.length();
if(startSelection > endSelection) {
    startSelection  = text.getSelectionEnd();
    endSelection = text.getSelectionStart();
}

Spannable str = text.getText();
StyleSpan[] ss = str.getSpans(startSelection, endSelection, StyleSpan.class);
for (int i = 0; i < ss.length; i++) {
    if (ss[i].getStyle() == android.graphics.Typeface.BOLD) {
        str.removeSpan(ss[i]);
    }
    if (ss[i].getStyle() == android.graphics.Typeface.ITALIC) {
        str.removeSpan(ss[i]);
    }
}

UnderlineSpan[] ulSpan = str.getSpans(startSelection, endSelection, UnderlineSpan.class);
for (int i = 0; i < ulSpan.length; i++) {
    str.removeSpan(ulSpan[i]);
}

str.removeSpan(ss[1]);

text.setText(str);
CarenRose
  • 1,266
  • 1
  • 12
  • 24
Rahul Gupta
  • 5,275
  • 8
  • 35
  • 66

6 Answers6

16

If you want remove all spans from text use this:

Spannable str = text.getText();    
Object spansToRemove[] = str.getSpans(startSelection, endSelection, Object.class);
    for(Object span: spansToRemove){
        if(span instanceof CharacterStyle)
            spannable.removeSpan(span);
    }
ramaral
  • 6,149
  • 4
  • 34
  • 57
  • 3
    `str.getSpans(startSelection, endSelection, CharacterStyle.class)` should return only the desired spans. – Wes Alvaro Apr 17 '19 at 04:16
  • and if you want to remove a specific span like style, you can use this as removedSpans:val spansToRemove = str.getSpans( et.selectionStart, et.selectionEnd,StyleSpan::class.java ), kotlin way. – Bita Mirshafiee Mar 27 '20 at 08:22
5

There is a very simple solution:

When you set the Spannable object to a TextView you use myTextView.setText(spannable); this adds your custom formatting of you assigned to the spannable.

In order to clear all the spans at once from the TextView use: myTextView.setText(spannable.toString());

Example

Spannable spannable = new SpannableString(myTextView.getText().toString());

spannable.setSpan(new ForegroundColorSpan(Color.RED), 8, 13,
        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

spannable.setSpan(new BackgroundColorSpan(Color.YELLOW), 4, 30, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
spannable.setSpan(new BackgroundColorSpan(Color.BLUE), 10, 20, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
spannable.setSpan(new UnderlineSpan(), 7, 11, 0);
myTextView.setText(spannable); // add all the spannable format
myTextView.setText(spannable.toString()); // clear all the spannable format
Zain
  • 37,492
  • 7
  • 60
  • 84
1

The following works for me (given that "text" is your TextView or EditText):

String str = text.getText().toString();
text.setText(str);
Ronen Rabinovici
  • 8,680
  • 5
  • 34
  • 46
0

I changed the code a little bit. Have a look. I have removed the if conditions inside the loop. It is working now.

fromSelectionSpan = true;
int startSelection = 0;
int endSelection = text.length();

Spannable str = text.getText();
StyleSpan[] ss = str.getSpans(startSelection, endSelection, StyleSpan.class);
for (int i = 0; i < ss.length; i++) {
    str.removeSpan(ss[i]);
}

UnderlineSpan[] ulSpan = str.getSpans(startSelection, endSelection, UnderlineSpan.class);
for (int i = 0; i < ulSpan.length; i++) {
    str.removeSpan(ulSpan[i]);
}

text.setText(str);
b.setChecked(false);
i.setChecked(false);
u.setChecked(false);
text.setSelection(endSelection);
CarenRose
  • 1,266
  • 1
  • 12
  • 24
Rahul Gupta
  • 5,275
  • 8
  • 35
  • 66
0

Here's a small utility method I created as an extension to TextView, tested in API 29:

fun TextView.removeAttributedProperties (forText: String? = null) {
  forText?.let {
    // 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
    }

    (text as? SpannedString)?.let { spannedString ->
        val spannable = spannedString.toSpannable()

        val spansToRemove = spannable.getSpans(startIdx, endIdx, CharacterStyle::class.java)
        for (span in spansToRemove) {
            spannable.removeSpan(span)
        }

        // update the text back
        text = spannable
    }
  } ?: run {
    // if we have no text, let's remove all attributed properties
    text = text.toString()
  }
}
KBog
  • 3,800
  • 1
  • 25
  • 31
0

Simple, re-initiate your SpannableString. Hope this will save your time.

Pratik Pitale
  • 1,655
  • 1
  • 16
  • 30