Android - Delete entire ImageSpan when part of it is deleted?
Asked Answered
S

3

5

I'm adding an image to my edittext by inserting an ImageSpan. I don't have a thorough understanding of spans but it seems that my ImageSpan needs to wrap a portion of text. So I add some text to the EditText, and wrap it with my ImageSpan and it appears fine. However, when I backspace the ImageSpan, it only deletes one character of the text and the image remains until the entire text is delete. How do I get it to just delete with one backspace?

SpannableStringBuilder builder = new SpannableStringBuilder();
builder.append(content.getText());

String imgId = "[some useful text]"; 

int selStart = content.getSelectionStart();

builder.replace(content.getSelectionStart(), content.getSelectionEnd(), imgId);

builder.setSpan(imageSpan, selStart, selStart+imgId.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
content.setText(builder);
Sarson answered 15/5, 2014 at 0:21 Comment(1)
it should remive the span after the first backspace, what os version are you using?Carbamate
G
7

After some time, I found solution. Try this code:

private TextWatcher watcher = new TextWatcher() {
    private int spanLength = -1;

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        if (start == 0) return;
        if (count > after) {
            ImageSpan[] spans = getEditableText().getSpans(start + count, start + count, ImageSpan.class);
            if (spans == null || spans.length == 0) return;
            for (int i = 0; i < spans.length; i++) {
                int end = getEditableText().getSpanEnd(spans[i]);
                if (end != start + count) continue;
                String text = spans[i].getSource();
                spanLength = text.length() - 1;
                getEditableText().removeSpan(spans[i]);
            }
        }
    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        if (spanLength > -1) {
            int length = spanLength;
            spanLength = -1;
            getEditableText().replace(start - length, start, "");
        }
    }

    @Override
    public void afterTextChanged(Editable s) {
    }
};

But you should create ImageStan with original String like this:

ssb.setSpan(new ImageSpan(bmpDrawable, originalStr), x, x + originalStr.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
Ghent answered 7/8, 2017 at 12:20 Comment(1)
Well, doesn't work on every device.. Can you please check my question here? #52943128Turpitude
B
1

Here's my stab on it:

field.doBeforeTextChanged { text, start, count, _ ->
            val spans = toField.text.getSpans<ImageSpan>(start = start + 1, end = start + 1 + count)
            for (span in spans) {
                toField.text.removeSpan(span)
            }
        }

Don't forget to replace ImageSpan with the one you are interested in.

Bukovina answered 1/2, 2020 at 22:3 Comment(0)
P
0

The above answers are useful. But be careful that: imagespan.source is used to save information about the image uri when you construct it! when you use ImageSpan, mSource is given the string value of the drawable resource connected to its uri Use contentDescription instead in Api 30 and above or do like this may help

private val watcher: TextWatcher = object : TextWatcher {
    override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
        if(s.isEmpty()) return
        // delete operation
        // from position 'start'
        // the tail of 's',with length 'count' would be erased 
        // for ime input reason, 'count' is always 1
        if(count>after){
            val spans: Array<ImageSpan> = article_publish_content.text.getSpans(
                0, start + count,
                ImageSpan::class.java
            )
            if (spans.isEmpty()) return
            // here sometimes you could use spans[spans.indices-1]
            // to reduce no-need traversal
            for (i in spans.indices) {
                val spanEnd: Int = article_publish_content.text.getSpanEnd(spans[i])
                val spanStart=article_publish_content.text.getSpanStart(spans[i])
                if (spanEnd != start + count) continue
                spanLength = spanEnd-spanStart
                article_publish_content.text.removeSpan(spans[i])
            }
        }
    }

    override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
        if (spanLength > -1) {
            val length = spanLength
            spanLength = -1
            var oStart=start-length
            if(oStart<0)
                oStart=0
            article_publish_content.text.replace(oStart, start, "")
        }
    }

    override fun afterTextChanged(s: Editable) {

    }
}
Promulgate answered 28/5, 2021 at 5:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.