12

i am working on an app in which user choose an image from gallery and it will be added in editText, now i want if user click on image in editText it should open in fullScreen, i used below code :-

public void addToEdt(Bitmap bitmap){
    SpannableString ss = new SpannableString("abc");
    Drawable d = new BitmapDrawable(getResources(), bitmap);
    d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
    ImageSpan span = new ImageSpan(d, ImageSpan.ALIGN_BASELINE);
    ss.setSpan(span, 0, 3, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
    edt_note.setTransformationMethod(null);
    edt_note.getText().insert(edt_note.getSelectionStart(), ss);

    final int start = ss.getSpanStart(span);
    final int end = ss.getSpanEnd(span);

    ClickableSpan click_span = new ClickableSpan() {
        @Override
        public void onClick(View widget) {
                   Toast.makeText(getApplicationContext(),"Clicked",Toast.LENGTH_LONG).show();
        }
    };

    ClickableSpan[] click_spans = ss.getSpans(start, end,  ClickableSpan.class);

    if(click_spans.length != 0) {
        // remove all click spans
        for (ClickableSpan c_span : click_spans) {
            ss.removeSpan(c_span);
        }
    }

    ss.setSpan(click_span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}

tried above code but its not listening onClick event, now, how can i listen click event on this image and do further task?

4 Answers4

16

Clickable Span at the same start and end locations of the editText.

sb.setSpan(cs, imageStartSpan,imageEndSpan , Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

Also

editText.setMovementMethod(LinkMovementMethod.getInstance());

I cannot write the whole code for you. Try the below sample:-

public void addToEdt(Bitmap bitmap){
    SpannableString ss = new SpannableString();
    Drawable d = new BitmapDrawable(getResources(), bitmap);
    d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
    ss.append("abc"); // Append the text here
    ImageSpan span = new ImageSpan(d, ImageSpan.ALIGN_BASELINE);
    ss.setSpan(span, 0, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); // start(0) and end (2) will create an image span over abc text
    ss.setSpan(new ClickableSpan() {
                @Override
                public void onClick(View widget) {
                    ss.delete(0, 2);
                    editText.setText(ss);
                }
            },0, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); // this will add a clickable span and on click will delete the span and text
    editText.setText(ss); // this will show your image/clickable span in edittext
}


editText.setMovementMethod(LinkMovementMethod.getInstance());
Rahul
  • 878
  • 9
  • 15
  • 1
    i tried setMovementMethod but its not working, will you please explain in detail, where should i change in my ABOVE code( addToEdt(Bitmap bitmap) method) –  Aug 18 '15 at 06:21
  • 1
    ImageSpan span = new ImageSpan(d, ImageSpan.ALIGN_BASELINE); ss.setSpan(span, 0, 3, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); Same way add clickablespan to same location start and end --> 0,3. – Rahul Aug 18 '15 at 06:29
  • 1
    sorry i dont get, can you edit my code and post as your answer , if its working i will accept your answer :) –  Aug 18 '15 at 06:45
  • 1
    Thanks alottttttttt man you made my day :), just one issue , by calling setMovementMethod , cursor of editText gone :o , now it looks odd, have any trick for this??? –  Aug 18 '15 at 20:14
  • 1
    hey rahul, why you delete span and text using ss.delete(0, 2);.......is there any specific purpose or its just for demo??? –  Aug 21 '15 at 18:04
  • It will delete the data from SpannableString and to reflect the same in Edittext, you can pass it to EditText. – Rahul Aug 24 '15 at 09:11
  • a repeat of the previous question - What happens if you don't delete the span? – Aadithya Feb 06 '17 at 22:22
5

I did not find using ClickableSpan and setMovementMethod to be acceptable given the problems it causes. I do not believe these were intended to be used in EditText control.

Also, I need to know WHERE the user clicked in the span. My image span has an X close button at the right side and I want to know if the user clicked on the X as opposed to just clicking on the label.

So I found another way:

  • Subclass ImageSpan and override the draw method to just call the super, but also to store the x/y/left/top in member variables - so, now you know where the span is positioned inside the EditText.
  • Subclass EditText and handle onTouchEvent to just call the super, but also get your spans and hit test each one to find out if the user tapped on the span (or a part of the span).

That's it, this method works with no side effects.

Greg Ennis
  • 14,917
  • 2
  • 69
  • 74
1

Try

final int start = ss.getSpanStart(span);
final int end = ss.getSpanEnd(span);

ClickableSpan click_span = new ClickableSpan() {
    @Override
    public void onClick(View widget) {

    }
};

ClickableSpan[] click_spans = ss.getSpans(start, end, ClickableSpan.class);

if(click_spans.length != 0) {
    // remove all click spans
    for (ClickableSpan c_span : click_spans) {
        ss.removeSpan(c_span);
    }
}

ss.setSpan(click_span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

Also add this:

yourEditText.setMovementMethod(LinkMovementMethod.getInstance());
  • 1
    Thanks, just trying out your code then will give you feedback :) –  Aug 16 '15 at 22:01
  • 1
    not working, fire a toast onClick but not listening to click event :( –  Aug 16 '15 at 22:07
  • @Nishusharma Take a look again please. Add the last line –  Aug 16 '15 at 22:09
  • 1
    i added setMovementMethod(LinkMovementMethod.getInstance()) to editText then it gives error when calling addToEdt(Bitmap bitmap); .......means after adding setMovementMethod i am not able even to add image :( –  Aug 16 '15 at 22:20
  • 1
    Hmm Take a look to these posts: http://stackoverflow.com/a/16182500/2528167 http://stackoverflow.com/a/6357661/2528167 –  Aug 16 '15 at 22:24
  • 1
    had seen but didnt found solution :( stackoverflow was the only hope for me ;( –  Aug 16 '15 at 22:41
  • Let someone else post his answer @Nishusharma –  Aug 16 '15 at 23:02
  • 2
    yeah, hope so....else i have to use imageView for this....although your answer didnt sort out the problem but still you tried to help me so i accepting your answer :) –  Aug 17 '15 at 09:37
0

I found another solution that is less intrusive than going with LinkMovementMethod. Instead, I simply extended ArrowKeyMovementMethod (the default movement method for EditText) and added some of the code from LinkMovementMethod that is used to determine the span that was clicked. In my case I looked for an ImageSpan and then deleted the text that span covered (so a click removes the image):

private class SpanDeletingMovementMethod : ArrowKeyMovementMethod() {
    override fun onTouchEvent(
        widget: TextView,
        buffer: Spannable,
        event: MotionEvent
    ): Boolean {
        if (event.action == MotionEvent.ACTION_DOWN) {
            var x = event.x.toInt()
            var y = event.y.toInt()
            x -= widget.totalPaddingLeft
            y -= widget.totalPaddingTop
            x += widget.scrollX
            y += widget.scrollY
            val layout = widget.layout
            val line = layout.getLineForVertical(y)
            val off = layout.getOffsetForHorizontal(line, x.toFloat())

            val committedTags = buffer.getSpans<ImageSpan>(off, off)
            if (committedTags.isNotEmpty()) {
                val tag = committedTags[0]
                (buffer as Editable).replace(buffer.getSpanStart(tag), buffer.getSpanEnd(tag), "")
                return true
            }
        }

        return super.onTouchEvent(widget, buffer, event)
    }
}

simply set this movement method on the EditText (or override getDefaultMovementMethod), and you can handle span clicks.

yawkat
  • 374
  • 2
  • 14