The problem:
To make a long story short, I would like to insert a custom clickable
Drawable
(or something that looks like a little button and acts like a single character) inside an EditText
.
Research:
I've read some documentation as well as related questions and I almost achieved the result I want (see "Code" section). It's a little bit tricky, but I wasn't able to find another way out. I'm using Html.fromHtml(source, imageGetter, tagHandler)
to insert the drawable I need with a link and then implementing a custom LinkMovementMethod
to handle clicks on it.
But there are some things I would like to avoid:
- If there are no text after my drawable, it gets clicked even if I click anywhere right to it. So I'm not able to place a cursor next to it without moving it manually.
- On some devices the cursor appears at the very beginning of
EditText
every time I perform a click, except cases when I click drawable.
Code:
Inserting drawable with a link and setting the custom LinkMovementMethod
:
Html.ImageGetter imgGetter = new Html.ImageGetter() {
@Override
public Drawable getDrawable(String source) {
Drawable drawable = getResources().getDrawable(R.drawable.blip_icon_read);
//Making it as small as a character
drawable.setBounds(0, 0, (int)getTextSize(), (int)getTextSize());
return drawable;
}
};
String buttonSrc = "<a href='button://" + "somedata" + "'><img src=/></a>";
myEditText.append(Html.fromHtml(buttonSrc, imgGetter, null));
myEditText.setMovementMethod(MyLinkMovementMethod.getInstance(context));
Custom LinkMovementMethod
:
public class MyLinkMovementMethod extends LinkMovementMethod {
private static Context movementContext;
private static MyLinkMovementMethod linkMovementMethod = new MyLinkMovementMethod();
public boolean onTouchEvent(android.widget.TextView widget, android.text.Spannable buffer, android.view.MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_UP) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
x += widget.getScrollX();
y += widget.getScrollY();
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
URLSpan[] link = buffer.getSpans(off, off, URLSpan.class);
if (link.length != 0) {
URI uri;
try {
uri = new URI(link[0].getURL());
} catch (URISyntaxException e) {
e.printStackTrace();
return true;
}
if (uri.getScheme().equals("button")) {
//Doing stuff here
}
return true;
}
}
return super.onTouchEvent(widget, buffer, event);
}
public static android.text.method.MovementMethod getInstance(Context c) {
movementContext = c;
return linkMovementMethod;
}
}
Layout:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<EditText
android:id="@+id/my_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
android:textColor="@android:color/black"
android:scrollbars="vertical"
android:textCursorDrawable="@null"
android:gravity="top" >
</EditText>
</LinearLayout>
Questions:
- Is there any way to avoid things I described in the end of "Research" section using this approach?
- Is there another approach I should use?
Will be glad to read advices or any ideas. Thank you.