11

I am actually trying to do card formatting, for that I am trying to implement what google says from link

You are not told where the change took place because other afterTextChanged() methods may already have made other changes and invalidated the offsets. But if you need to know here, you can use setSpan(Object, int, int, int) in onTextChanged(CharSequence, int, int, int) to mark your place and then look up from here where the span ended up.

From above what I understand is I need to save [CharSequence s, int start, int before, int count] using setSpan in onTextChanged() and somehow retrieve them back in afterTextChanged().

Question is, on which object do I call setSpan() in onTextChanged() and how do I retrieve those saved values in afterTextChanged().

T_C
  • 3,148
  • 5
  • 26
  • 46
  • 2
    I'm wondering the same thing, for an almost identical use case. Did you ever figure this out? – MW. Apr 21 '15 at 06:48

1 Answers1

10

So I figured this one out. Below is a barebones example that can be used as a starting point.

import android.text.Editable;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextWatcher;
import android.text.style.RelativeSizeSpan;

public class AwesomeTextWatcherDeluxe implements TextWatcher {

    private RelativeSizeSpan span;
    private SpannableString spannable;


    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        // We can use any span here. I use RelativeSizeSpan with size 1, which makes absolutely nothing.
        // Perhaps there are other spans better suited for it?
        span = new RelativeSizeSpan(1.0f);
        spannable = new SpannableString(s);
        spannable.setSpan(span, start, start + count, Spanned.SPAN_COMPOSING);
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {

    }

    @Override
    public void afterTextChanged(Editable s) {
        int beginIndex = spannable.getSpanStart(span);
        int endIndex = spannable.getSpanEnd(span);

        // Do your changes here.

        // Cleanup
        spannable.removeSpan(span);
        span = null;
        spannable = null;
    }
}
MW.
  • 12,550
  • 9
  • 36
  • 65
  • Wow, that looks horrifying. I kinda messed with it around too, and found out that you basically can cast CharSequence s to Spannable, since in most cases parameter s is a subclass, that implements Spannable as a span object you can use TextWatcher itself (pass this). – kravitz Jan 28 '18 at 10:53
  • It works! Also using a plain `Object`, created just once, instead of `RelativeSizeSpan`, and using 0 as flags to `setSpan()`. `private Object span = new Object(); ...; spannable.setSpan(span, start, start + count, 0);` – PJ_Finnegan Jul 09 '20 at 14:54