Android - long pressing to open the context menu on a TextView also triggers an autoLink click

2.2k views Asked by At

I have a TextView that launches a context menu:

textView.setOnCreateContextMenuListener(new OnCreateContextMenuListener() {
            @Override
            public void onCreateContextMenu(ContextMenu contextMenu, 
                                            View view,
                                            ContextMenu.ContextMenuInfo contextMenuInfo) {
                // Do stuff... 
            }
        });

This textview also has the android:autoLink="all" attribute set in its XML.

Now, if I set the contents of the TextView to a URL and long press over the URL, the context menu appears first, but when I lift my finger the link is pressed and opens the browser.

Is there any way to have the context menu or the long press consume the touch event so that the link is not clicked? I have considered overriding onTouch() for the TextView to handle ACTION_UP events, but I cannot reliably keep track of when the context menu is visible to block the touch event.

3

There are 3 answers

2
Mike M. On

This seems somewhat hacky to me, but it's the only way I've been able to make this work without directly handling the View's touch events (which may very well be the proper method).

We're essentially changing out the TextView's LinkMovementMethod if the context menu opens, so the up action doesn't fire the link. When the context menu closes, we restore the LinkMovementMethod so that normal clicks on links work as expected.

Adjust your onCreateContextMenu() method as follows:

textView.setOnCreateContextMenuListener(new OnCreateContextMenuListener() {
        @Override
        public void onCreateContextMenu(ContextMenu menu,
                                        View view,
                                        ContextMenu.ContextMenuInfo info) {
            textView.setMovementMethod(ArrowKeyMovementMethod.getInstance());
            // Do stuff
        }
    });

Then override the Activity's onContextMenuClosed() like so:

@Override
public void onContextMenuClosed(Menu menu)
{
    textView.setMovementMethod(LinkMovementMethod.getInstance());
}

Of course, this assumes that textView is a class member of your Activity.

0
SixBangs On

This solution doesn't seem to have any drawbacks:

override fun onCreateContextMenu(menu: ContextMenu, view: View, menuInfo: ContextMenuInfo) {
    // Inflate your menu, etc

    // ...

    // Cancel any tap in progress
    view.dispatchTouchEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0f, 0f, 0))
}

Long press will show the context menu as expected, but nothing will happen when you lift your finger (because the tap has already been cancelled). Short taps that do not result in a context menu will be handled as usual.

0
yefeng On

Just like Mike M. said.

you can use setOnCreateContextMenuListener instead. and perform click parent's view in this method

Example:

here is a textview inside a viewgroup;

textview.setOnCreateContextMenuListener(
(menu, v, menuInfo) -> viewgroup.performLongClick());