Delete entire ImageSpan when the part of it is deleted
Asked Answered
S

1

1

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?

Simply answered 23/10, 2018 at 6:39 Comment(2)
did you got any solution?Jetta
@Jetta wait a minute, I'll post an answer in a minute.Simply
S
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.

Simply answered 14/6, 2019 at 7:22 Comment(5)
Thank you for answer but it's not working in Samsung S8 Oreo. How you are applying image span? what is EmojiSpan class?Jetta
I'm using custom span with DynamicDrawableSpan as parent. I can upload snipped if you want to try.Simply
This is my EmojiSpan class snipsave.com/denunknown/#/snippet/XX4ABLJRmF939eJTlXSimply
Ok but it's not working for me. In my case start is always 0 when I have continues emoji(Imagespan) without space.Jetta
I don't know, this is how i span: snipsave.com/denunknown/#/snippet/hOhdcn1L1kpHHmxqAGSimply

© 2022 - 2024 — McMap. All rights reserved.