3

I'm using setMovementMethod(LinkMovementMethod.getInstance()) for EditText view in my android app. Links inside EditText works fine but in some situations I need programly disable this method (for reason of enable copy item in longClick menu). How to do it? I need something like "removeMovementMethod()".

Can you help me?

Thank you!

lubart
  • 1,746
  • 3
  • 27
  • 35

7 Answers7

4

After facing the same issue as well, please consider, there seems to be a certain sequence of setting the methods.

  1. Get the 'TextView'
final TextView tv = new TextView(getContext());
  1. Set all necessary layout parameter
tv.setLayoutParams(lp_tv);
  1. Set the Linkify to mark all links in the text as Link
tv.setAutoLinkMask(Linkify.ALL);
  1. Set the content of the TextView (after the setAutoLinkMask)
tv.setText("MyText")
tv.setText(Html.fromHtml("<big>MyText</big>");
  1. Now you can attach the LinkMovementMethod. If the method is attached earlier, it will call the default behavior and open the system browser. I use a TextViewLinkHandler class to do the job as individual behavior. The standard behavior is:
tv.setLinkMovementMethod(new LinkMovementMethod.getInstance());

I use the TextViewLinkHandler to do some other stuff if the user clicks a link (e.g. opening an individual Intent to process the URL)

 tv.setMovementMethod(new TextViewLinkHandler() {
// do my stuff ... 
// if left blank, nothing will happen on click at the link, so leave it blank to do nothing
});

With the mentioned TextViewLinkHandler()

public abstract class TextViewLinkHandler extends LinkMovementMethod {

        public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
            if (event.getAction() != MotionEvent.ACTION_UP)
                return super.onTouchEvent(widget, buffer, event);

            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) {
                onLinkClick(link[0].getURL());
            }
            return true;
        }

        abstract public void onLinkClick(String url);
    }
Ricardo Gonzalez
  • 1,827
  • 1
  • 14
  • 25
2
setMovementMethod(null)

would set the textview's movementmethod to null. This could of course cause a NullPointerException if your code wants to handle the MovementMethod in some way.

keyser
  • 18,829
  • 16
  • 59
  • 101
  • Thank you for your reply! In general, answer is right and after `setMovementMethod(null)` links does not work but there is no react on longClick event as well. I need copy text from EditText but it item is disable after `setMovementMethod(LinkMovementMethod.getInstance())` I'm finding some solving of this problem. May be you have some ideas? Thank you! – lubart May 13 '12 at 18:33
  • I tried re-attaching the LongClicklistener but it have no effect :( Is some default value for setMovementMethod(null) it looks like that this value != null. – lubart May 13 '12 at 19:01
  • Sorry it has no effect again. After `setMovementMethod(null)` these is no possibility to call longClick menu even after call `setOnLongClickListener()` :( – lubart May 13 '12 at 19:47
  • yes, I used `edittext.setMovementMethod(LinkMovementMethod.getInstance())` and after that i have not copy item on longClick menu, but after `edittext.setMovementMethod(null)` i have not longClick menu at all... and edittext.setFocusable(true) did not help... – lubart May 13 '12 at 19:52
  • @lubart try [this](http://stackoverflow.com/questions/3602931/edittext-setmovementmethod-with-linkmovement-method-in-listview-loses-ability) and [this](http://stackoverflow.com/questions/2679948/focusable-edittext-inside-listview) – keyser May 14 '12 at 07:26
2

After setMovementMethod(null) longClick menu will disable. Therefore better use this method:

setMovementMethod(ArrowKeyMovementMethod.getInstance())
lubart
  • 1,746
  • 3
  • 27
  • 35
  • i didnt find such method. is there in android – Krishna Shrestha May 16 '12 at 13:32
  • thanks i got it too. but it doesn't help on on click span though it works fine long click. is there any beside – Krishna Shrestha May 17 '12 at 07:13
  • 2
    before `setMovementMethod(LinkMovementMethod.getInstance())` you can try `Log.v("movement", et.getMovementMethod())` check the value and in some command back to this value again with `et.setMovementMethod(VALUE)`. – lubart May 17 '12 at 08:00
  • et.getMovementMethod() gives a resource type value android.text.Method.ArroKeyMovementMethod@40521f10. what does this mean?? if set that i am not able to delete spanned text on click.ontouch with in edittext.:( – Krishna Shrestha May 17 '12 at 09:18
  • aLSO IF IS SET LinkMovemetMethod method i am not unable to place the cursor postion to the end of spanntext. and if i didnt set LinkMovementMethod before clickable span i am not able to delete spanntext on onclick. any suggestion?? – Krishna Shrestha May 17 '12 at 09:28
  • 1. value `android.text.Method.ArrowKeyMovementMethod@40521f10` means that you have instance of `ArrowKeyMovementMethod()`, that is why for disable `setMovementMethod(LinkMovementMethod.getInstance())` and back to "default" you need write `editText.setMovementMethod(ArrowKeyMovementMethod.getInstance())` 2. with LinkMovemetMethod method cursor will disable and you need use ArrowKeyMovementMethod for have cursor... I solved this problem with switching between this two methods – lubart May 17 '12 at 15:36
  • it didnt work for me. can u explain a bit more??... i will be thankful to u – Krishna Shrestha May 20 '12 at 07:42
  • thanks for ur helping nature. here is my scenario, i have set spanableString in edittext.I want to delete spannable text set when user touch on it. for that i added clickable span.For making clickable span to work, i set movementment method to LinkMovementMethod.getInstance(). and it works fine but when i set this property Cursor becomes disable in edittext. and cursor always point at the first. i tried edittext.setSelection(int index) for moving cursor at the end of text on edittext but it didnt work.if i didnt set linkMovementMethod set selection works. – Krishna Shrestha May 22 '12 at 05:22
  • i want to cursor at the end of text in edittext and delete to work on touch of spanable text At a time. how can i solve?? – Krishna Shrestha May 22 '12 at 05:23
  • If you need to write in EditText all the time you should not use LinkMovementMethod.getInstance() because, as you corrected said, after using it you will have a cursor and will not write. You should to think in direction button inside edittext, may be some of this articles will help you http://arunbadole1209.wordpress.com/2011/12/16/how-to-create-edittext-with-crossx-button-at-end-of-it/ , http://stackoverflow.com/questions/3018050/how-to-embed-a-view-with-buttons-etc-inside-an-edittext good luck! – lubart May 22 '12 at 16:54
  • thanks again for ur refrence. but it can be done as gosmspro app is doing it. – Krishna Shrestha May 23 '12 at 03:56
0

Like @lubart commented in one of the answers, setting setMovementMethod(null) will not work. You would need to save the previous MovementMethod before setting LinkMovementMethod and restore it again when you do not want to use LinkMovementMethod.

One important thing I want to highlight is that you would have to set AutoLinkMask=0 when restoring back to previous MovementMethod otherwise the links will not go away, the caret will not show and the copy/paste context menu will not appear.

Also, after using setMovementMethod, set the text again in EditText/TextView in order to apply the movement method.

Algorithms (Not the code):

To set link movement method -

previousMovementMethod = editText.MovementMethod;

editText.autoLinkMask = All;
editText.MovementMethod = LinkMovementMethod.GetInstance();
editText.SetText(editText.GetText());

To remove link movement method -

editText.autoLinkMask = 0;
editText.MovementMethod = previousMovementMethod;
editText.SetText(editText.GetText());
Gautam Jain
  • 6,789
  • 10
  • 48
  • 67
0

Try it :- add this class in your project

import android.text.Layout;
import android.text.Selection;
import android.text.Spannable;
import android.text.method.ArrowKeyMovementMethod;
import android.text.method.MovementMethod;
import android.text.style.ClickableSpan;
import android.view.MotionEvent;
import android.widget.TextView;

/**
 * Created by Nishu on 20-08-2015.
 */
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);
 }

}

now add below line of code with your EditText

YourEditText.setMovementMethod(MyMovementMethod.getInstance());

and remove all type of setMovementMethods from editText Thats it :)

0

As user5211136 said you can use custom ArrowKeyMovementMethod. Then the text will be selectable and hyperlinks will work too. But the using of class of user5211136 called error

"Actvity was not found for intent, Intent { act=android.intent.action.VIEW dat= https://... (has extras) }"

for me.

That's why I used this class:

public class CustomArrowKeyMovementMethod extends ArrowKeyMovementMethod {

    public static MovementMethod getInstance(){
        return new CustomArrowKeyMovementMethod();
    }

    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);

            URLSpan[] link = buffer.getSpans(off, off, URLSpan.class);

            if (link.length != 0) {
                if (action == MotionEvent.ACTION_UP) {
                    String url = link[0].getURL().trim();
                    if(url.startsWith("www")) {
                        url = "http://" + url;
                    }
                    if (url.startsWith("https://") || url.startsWith("http://") || url.startsWith("tel:") || url.startsWith("mailto:")) {
                        try {
                            Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
                            widget.getContext().startActivity(browserIntent);
                        } catch (Exception e) {
                            Toast.makeText(widget.getContext(), "Couldn't open url", Toast.LENGTH_LONG).show();
                        }
                    }
                } else {
                    Selection.setSelection(buffer, buffer.getSpanStart(link[0]), buffer.getSpanEnd(link[0]));
                }
                return true;
            }
        }
        return super.onTouchEvent(widget, buffer, event);
    }
}

And called it as:

textView.setMovementMethod();
Eugene Babich
  • 1,271
  • 15
  • 25
0

You can use the etNote.autoLinkMask =0 for disable and etNote.autoLinkMask=Linkify.ALL to again enable all link proide one button to do so.

below is full code work in 2023 Android kotlin.

Provide below in onViewCreated to initially enable all links.

    try {
          etNote.movementMethod = LinkMovementMethod.getInstance()
          etNote.autoLinkMask = Linkify.ALL
          //etNote.setLinkTextColor(Color.parseColor("#077641"))
        } catch (e: Exception) {}

    btnHyperlinkOnOff.setOnClickListener {

        if (btnHyperlinkOnOff.text == "  Hyperlink Enable")
        {
            etNote.autoLinkMask =0
            //etNote.setLinkTextColor(Color.parseColor("#0C0C0C"))
            btnHyperlinkOnOff.text = "  Hyperlink Disable"

            //Refresh the etNote with same text to get the hyperlink disable effect...
            val contents = etNote.text.toString()
            etNoteAllowSave =false // Indirect disable afterTextChanged
            etNote.setText(contents + "\n\n\n") //set data
            etNoteAllowSave =true // Once set data done - Indirect enable afterTextChanged
        }
        else
        {
            etNote.autoLinkMask = Linkify.ALL
            //etNote.movementMethod = LinkMovementMethod.getInstance()
           // etNote.setLinkTextColor(Color.parseColor("#077641"))
            btnHyperlinkOnOff.text = "  Hyperlink Enable"

            //Refresh the etNote with same text to get the hyperlink disable effect...
            val contents = etNote.text.toString()
            etNoteAllowSave =false // Indirect disable afterTextChanged
            etNote.setText(contents + "\n\n\n") //set data
            etNoteAllowSave =true // Once set data done - Indirect enable afterTextChanged
        }
    }
sandip
  • 394
  • 1
  • 4
  • 11