2016-04-03 127 views
1

有沒有辦法阻止用戶刪除或修改EditText中的spannable?更具體地說,我有一個ImageSpan作爲EditText的第一個字符。我想確保用戶不能刪除該ImageSpan。如何防止刪除EditText中的spannable

我意識到我可以使用TextWatcher並在用戶刪除它時替換ImageSpan。這是相當醜陋的,我希望有一種方法來防止首先刪除。

下面是一個代碼剪斷,我設置文本值:

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

有很多方法可以完成你想要的功能,比如設置一個自定義的'InputFilter'或者創建一個'TextView'的子類,並提供你自己的'InputConnection'實現,並覆蓋一些方法。但是使用'TextWatcher'是我知道的最簡單的解決方案。 – Michael

+0

所以,你是說沒有Spannable屬性來設置處理這個? –

+0

有一種方法我沒有提到。我會寫它作爲答案。 – Michael

回答

4

OK,該解決方案是非常複雜的,但它的工作。我們需要一個自定義InputFilter和一個SpanWatcher。開始吧。

第一步很簡單。我們設置一個帶有圖像跨度的不可編輯前綴,並在該前綴後面設置光標。

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()); 

然後我們設置一個InputFilter,以防止與編輯跨度的前綴。可以通過移動正在編輯的範圍,使其在前綴後面開始。

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; 
     } 
     } 
    } 
}); 

然後我們創建一個SpanWatcher,能夠檢測選擇的變化和移動選擇了前綴範圍。

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); 
     } 
    } 
    } 
}; 

最後我們只是將SpanWatcher添加到文本中。

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

而就是這樣。因此,比較這種解決方案,只是增加一個TextWatcher我寧願後一種方法。

+0

我還沒有通過你的代碼,但我很肯定你投入它的時間。人們會認爲谷歌會更容易攔截輸入到EditText中的字符! –

+0

在我看來'TextView'是最複雜的UI組件之一。用它做一些明顯的事情真的很難。 – Michael