title: How to use a SpanWatcher in Android?
body: <p>I've been trying to find a work around to an <a href="http://code.google.com/p/android/issues/detail?id=14786" rel="noreferrer">android issue with zero length formatting Spans</a>. I figured, ok, I'll just delete Spans that become zero length. After some looking around I figured a SpanWatcher would be a good way to do this. However there seems to be a lack of examples on how to implement or add SpanWatchers.</p>
  
  <p>I tried this in MonoDroid:</p>
  
  <pre><code>public class PreventZeroLenSpan : Java.Lang.Object, ISpanWatcher
  {
      void ISpanWatcher.OnSpanAdded (ISpannable text, Java.Lang.Object what, int start, int end)
      {
          if (what==this) return;
          var CS = what as Android.Text.Style.CharacterStyle;
          if (CS==null) return;
          if (start==end) text.RemoveSpan(CS);
      }
  
      void ISpanWatcher.OnSpanChanged (ISpannable text, Java.Lang.Object what, int ostart, int oend, int nstart, int nend)
      {
          if (what==this) return;
          var CS = what as Android.Text.Style.CharacterStyle;
          if (CS==null) return;
          if (nstart==nend) text.RemoveSpan(CS);
      }
  
      void ISpanWatcher.OnSpanRemoved (ISpannable text, Java.Lang.Object what, int start, int end)
      {
          // nothing
      }
  }
  </code></pre>
  
  <p>And the events get called if I add it directly to SpannableStringBuilder or SpannableString before anything else, but after it goes into an EditText control it no longer responds.</p>
  
  <pre><code>        var Str = new SpannableStringBuilder("Test IT");
          var Sty = new ForegroundColorSpan(Android.Graphics.Color.Blue);
          Str.SetSpan(SpanWatch,0,Str.Length(), SpanTypes.InclusiveInclusive);
          Str.SetSpan(Sty,5,7, SpanTypes.InclusiveInclusive);
          txEdit.SetText(Str, TextView.BufferType.Editable);
  </code></pre>
  
  <p>SpanWatcher implements NoCopySpan, so it doesn't get copied into EditText. I can't find any methods to add SpanWatcher directly to EditText (there is a method to add a TextWatcher).</p>
  
  <p>I suppose if I can't figure out SpanWatcher, I could scan the entire contents for zero length spans every time text changes. It just seems inefficient. (And I may need the removal event for my graphical newline indicators later.)</p>
  
  <p>Any ideas are appreciated, examples in Java or MonoDroid are welcome.</p>
  
  <p><strong>EDIT</strong></p>
  
  <p>I'm still interested to know how to do this with SpanWatcher (seems more efficient), but for anyone else struggling with zero length Span removal, you could do EditText.AddTextChangedListener() with the following TextWatcher:</p>
  
  <pre><code>public class PreventZeroLenSpanWatcher : Java.Lang.Object, ITextWatcher
  {
      void ITextWatcher.AfterTextChanged (IEditable s)
      {
          var Objs = s.GetSpans(0,s.Length(), Java.Lang.Class.FromType(typeof(Android.Text.Style.CharacterStyle)));
          foreach (Android.Text.Style.CharacterStyle CS in Objs)
          {
              int Start = s.GetSpanStart(CS);
              int End = s.GetSpanEnd(CS);
              if (Start == End) s.RemoveSpan(CS);
          }
      }
  
      void ITextWatcher.BeforeTextChanged (Java.Lang.ICharSequence s, int start, int count, int after)
      {
          // nothing
      }
  
      void ITextWatcher.OnTextChanged (Java.Lang.ICharSequence s, int start, int before, int count)
      {
          // nothing
      }
  }
  </code></pre>
  
  <p><strong>EDIT2</strong></p>
  
  <p>If you do this, you can at least get SpanWatcher into the EditText, but once user edits text you seem to loose it again. There must be some copying that takes place internally by the control and the SpanWatcher is not copyable.</p>
  
  <pre><code>        IEditable txEditFormatted = ((IEditable)txEdit.TextFormatted);
          txEditFormatted.SetSpan(SpanWatch,0,txEditFormatted.Length(), SpanTypes.InclusiveInclusive);
  </code></pre>
  
  <p>I also tried using a TextWatcher to re-add the SpanWatcher but by that time the spans were already altered.</p>