如何防止删除EditText中的spannable

时间:2016-04-03 16:39:21

标签: android spannable

有没有办法阻止用户删除或修改EditText中的spannable?更具体地说,我有一个ImageSpan作为EditText的第一个字符。我想确保用户无法删除ImageSpan。

我意识到如果用户删除它,我可以使用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);

1 个答案:

答案 0 :(得分:4)

好的,解决方案非常复杂,但它的工作正常。我们需要自定义InputFilterSpanWatcher。让我们开始。

第一步很简单。我们使用图像范围设置不可编辑的前缀,并在此前缀后设置光标。

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进行比较,我更倾向于采用后一种方法。