2016-04-03 8 views
1

Gibt es eine Möglichkeit zu verhindern, dass ein Benutzer in einem EditText ein spannbares Objekt löschen oder ändern kann? Genauer gesagt, habe ich einen ImageSpan als erstes Zeichen des EditText. Ich möchte sicherstellen, dass der Benutzer dieses ImageSpan nicht löschen kann.Wie kann man verhindern, dass in einem EditText ein spannbares Objekt gelöscht wird?

Ich weiß, ich kann TextWatcher verwenden und ImageSpan ersetzen, wenn der Benutzer es löscht. Das ist ziemlich hässlich und ich hoffe, dass es einen Weg gibt, die Löschung von vornherein zu verhindern.

Hier ist ein Schnipsel von Code, in dem ich den Text Wert:

Bitmap bitmap = <bitmap from elsewhere>; 
String text = <text to display after ImageSpan, from elsewhere>; 

SpannableString ss = new SpannableString (" " + text); 
ImageSpan image = new ImageSpan (getContext(), bitmap, ImageSpan.ALIGN_BOTTOM); 
ss.setSpan (image, 0, 1, 0); 

setText (ss); 
+0

Es gibt mehrere Möglichkeiten, wie Sie einen benutzerdefinierten 'InputFilter' oder eine'TextView'unterklassifizieren und eine eigene Implementierung von' InputConnection' mit einigen überschriebenen Methoden bereitstellen können. Aber die Verwendung eines 'TextWatcher' ist die einfachste Lösung, die mir bekannt ist. – Michael

+0

Also, sagen Sie, es gibt keine spannbaren Eigenschaften, um dies zu handhaben? –

+0

Es gibt eine Methode, die ich nicht erwähnt habe. Ich werde es als Antwort schreiben. – Michael

Antwort

4

OK, ist die Lösung ziemlich kompliziert, aber es funktioniert. Wir benötigen eine benutzerdefinierte InputFilter und eine SpanWatcher. Lasst uns beginnen.

Der erste Schritt ist ziemlich einfach. Wir setzen ein nicht editierbares Präfix mit einer Bildspanne und setzen einen Cursor nach diesem Präfix.

final String prefix = "?"; 
final ImageSpan image = new ImageSpan(this, R.drawable.image); 

edit.setText(prefix); 
edit.getText().setSpan(image, 0, prefix.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 
edit.setSelection(prefix.length()); 

Dann setzten wir ein InputFilter, die das Präfix mit der Spanne von der Bearbeitung verhindern. Sie können einen Bereich bearbeiten, der bearbeitet wird, sodass er nach dem Präfix beginnt.

edit.setFilters(new InputFilter[] { 
    new InputFilter() { 
     @Override 
     public CharSequence filter(final CharSequence source, final int start, 
      final int end, final Spanned dest, final int dstart, final int dend) { 
     final int newStart = Math.max(prefix.length(), dstart); 
     final int newEnd = Math.max(prefix.length(), dend); 
     if (newStart != dstart || newEnd != dend) { 
      final SpannableStringBuilder builder = new SpannableStringBuilder(dest); 
      builder.replace(newStart, newEnd, source); 
      if (source instanceof Spanned) { 
      TextUtils.copySpansFrom(
       (Spanned) source, 0, source.length(), null, builder, newStart); 
      } 
      Selection.setSelection(builder, newStart + source.length()); 
      return builder; 
     } else { 
      return null; 
     } 
     } 
    } 
}); 

Dann erstellen wir eine SpanWatcher die Auswahl ändert und bewegen Sie die Auswahl aus dem Präfix Bereich erkennt.

final SpanWatcher watcher = new SpanWatcher() { 
    @Override 
    public void onSpanAdded(final Spannable text, final Object what, 
     final int start, final int end) { 
    // Nothing here. 
    } 

    @Override 
    public void onSpanRemoved(final Spannable text, final Object what, 
     final int start, final int end) { 
    // Nothing here. 
    } 

    @Override 
    public void onSpanChanged(final Spannable text, final Object what, 
     final int ostart, final int oend, final int nstart, final int nend) { 
    if (what == Selection.SELECTION_START) { 
     if (nstart < prefix.length()) { 
     final int end = Math.max(prefix.length(), Selection.getSelectionEnd(text)); 
     Selection.setSelection(text, prefix.length(), end); 
     } 
    } else if (what == Selection.SELECTION_END) { 
     final int start = Math.max(prefix.length(), Selection.getSelectionEnd(text)); 
     final int end = Math.max(start, nstart); 
     if (end != nstart) { 
     Selection.setSelection(text, start, end); 
     } 
    } 
    } 
}; 

Und schließlich fügen wir nur die SpanWatcher auf den Text.

edit.getText().setSpan(watcher, 0, 0, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 

Und das ist alles. Bei einem Vergleich dieser Lösung mit einer TextWatcher würde ich den letzteren Ansatz bevorzugen.

+0

Ich habe Ihren Code noch nicht durchgelesen, aber ich schätze die Zeit, die Sie hineingesteckt haben. Man könnte meinen, Google würde es einfacher machen, Charaktere abzufangen, die in einen EditText eingegeben wurden! –

+0

Meiner Meinung nach ist 'TextView' eine der kompliziertesten UI-Komponenten. Es kann sehr schwierig sein, einige offensichtliche Dinge damit zu tun. – Michael