I have an EditText
view in my Android app. I need "inner links" in it, this means that I need some buttons or span inside EditText
and with onClick
to this button I can do some actions (not redirect to web page).
I realized this buttons with ClickableSpan()
like this
linkWord = "my link";
link = new SpannableString(linkWord);
cs = new ClickableSpan(){
private String w = linkWord;
@Override
public void onClick(View widget) {
wrd.setText(w);
}
};
link.setSpan(cs, 0, linkWord.length(), 0);
et.append(link);
For make this span clickable I used
et.setMovementMethod(LinkMovementMethod.getInstance());
"Inner links" works fine, but after using et.setMovementMethod()
copy and paste items are disable on OnLongClick
menu. And this is a problem, because I need "links" in EditText
and copy text from this view in the same time.
I have idea to set in listener OnLongClickListener
something like removeMovementMethod()
for temporary disable "links" function and use menu with copy/paste and after coping text switch on setMovementMethod()
method again. But I don't know how to realize this.
Can you help me? You may be there are some another ways...
Thank you!
I don't think that having the user switch between link and copy mode will win you a usability prize. My solution allows you to select text and open the links at the same time. To achieve this I simply extend ArrowKeyMovementMethod, which allows to select text, and add the onTouchEvent() method from the LinkMovementMethod which handles the clicking/touching of links. There's but one line of code that needs to be changed, which is the one removing the selection from the TextView when no link could be found at the coordinates the screen was touched.
Here's the complete class:
public class MyMovementMethod extends ArrowKeyMovementMethod {
private static MyMovementMethod sInstance;
public static MovementMethod getInstance() {
if (sInstance == null) {
sInstance = new MyMovementMethod ();
}
return sInstance;
}
@Override
public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_UP ||
action == MotionEvent.ACTION_DOWN) {
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);
ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);
if (link.length != 0) {
if (action == MotionEvent.ACTION_UP) {
link[0].onClick(widget);
}
else if (action == MotionEvent.ACTION_DOWN) {
Selection.setSelection(buffer, buffer.getSpanStart(link[0]), buffer.getSpanEnd(link[0]));
}
return true;
}
/*else {
that's the line we need to remove
Selection.removeSelection(buffer);
}*/
}
return super.onTouchEvent(widget, buffer, event);
}
}
Doing this is pretty safe even if the documentation states:
This interface [MovementMethod] is intended for use by the framework; it should not be implemented directly by applications. http://developer.android.com/reference/android/text/method/MovementMethod.html
The code above extends a documented class rather than implement the interface. All it does is adding a check to see if a link was tapped and otherwise uses the super class methods.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With