问题
I'm trying to implement Emoji's in my app and I should use short codes (like :dog:
, :cat:
), not unicode. I have two devices to test on and two different behaviours of EditText
and ImageSpan
in it.
First: Meizu PRO 6, Android 6.0 (API 23)
Everything works as I want. When you tap backspace on the spanned text, it disappears from EditText completely, because full spanned part of the string was removed.
For example, you have a "Hello :dog:
" in your EditText
(:dog:
is replaced with a picture of the dog), you press backspace, your EditText contains only "Hello " now.
Second: Google Pixel XL, Android 9.0 (API 28)
When you tap backspace on the spanned text, you just remove the :
symbol, making picture stay in EditText because it doesn't remove all spanned part of your string. But I want to remove it.
What did I try
I found this code in the other question here:
Android - Delete entire ImageSpan when part of it is deleted?
private val watcher = object : TextWatcher {
private var spanLength = -1
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
if (start == 0) return
if (count > after) {
val spans =
editableText.getSpans(start + count, start + count, ImageSpan::class.java)
if (spans == null || spans.isEmpty()) return
for (i in spans.indices) {
val end = editableText.getSpanEnd(spans[i])
if (end != start + count) continue
val text = spans[i].source
spanLength = text!!.length - 1
editableText.removeSpan(spans[i])
}
}
}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, after: Int) {
if (spanLength > -1) {
val length = spanLength
spanLength = -1
editableText.replace(start - length, start, "")
}
}
override fun afterTextChanged(s: Editable) {}
}
It works as intended for Google Pixel XL, but completely brakes Meizu removing 2-3 pictures or even not spanned text, sometimes it throws an Exception because start - length < 0
.
Is there any way to solve this?
回答1:
I ended up with this TextWatcher
private val watcher = object : TextWatcher {
private var spanLength = -1
private var spanStart = -1
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
if (start == 0) return
if (count > after) {
val spans =
editableText.getSpans(start + count, start + count, EmojiSpan::class.java)
if (spans == null || spans.isEmpty()) return
for (i in spans.indices) {
val end = editableText.getSpanEnd(spans[i])
if (end != start + count) continue
val text = spans[i].getSource()
spanLength = text.length - 1
spanStart = editableText.getSpanStart(spans[i])
editableText.removeSpan(spans[i])
}
}
}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
if (spanLength > -1 && spanStart != -1 && count < before) {
val startSpan = spanStart
val endSpan = spanStart + spanLength
if (startSpan < 0 || endSpan > editableText.length) {
return
}
spanLength = -1
spanStart = -1
editableText.replace(startSpan, endSpan, "")
}
}
override fun afterTextChanged(s: Editable) {}
}
Looks like it works with all devices I've tried.
来源:https://stackoverflow.com/questions/52942628/delete-entire-imagespan-when-the-part-of-it-is-deleted