Длинный щелчок по кликабельному промежутку не срабатывает до тех пор, пока щелчок не будет отпущен

Мне нужен интерактивный диапазон, чтобы в моем приложении были как обычные, так и длинные методы щелчка, и я узнал здесь (В Android - как я могу регистрировать только длинные клики с помощью ClickableSpan), что я мог бы расширить класс LinkMovementMethod и класс ClickableSpan, чтобы разрешить делать что, но в настоящее время работают и длинные, и короткие щелчки, но для длинного щелчка вместо запуска действия длинного щелчка, когда элемент был нажат достаточно долго, он будет ждать, пока вы не отпустите элемент, чтобы выстрелить. Вот мой код для расширенных классов:

LinkMovementClass

import android.text.Layout;
import android.text.Selection;
import android.text.Spannable;
import android.text.method.LinkMovementMethod;
import android.text.method.MovementMethod;
import android.view.MotionEvent;
import android.widget.TextView;

public class LongClickLinkMovementMethod extends LinkMovementMethod {

private Long lastClickTime = 0l;
private int lastX = 0;
private int lastY = 0;
@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();
        lastX = x;
        lastY = y;
        int deltaX = Math.abs(x-lastX);
        int deltaY = Math.abs(y-lastY);

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

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

        if (link.length != 0) {
            if (action == MotionEvent.ACTION_UP) {
                if (System.currentTimeMillis() - lastClickTime < 1000)
                    link[0].onClick(widget);
                else if (deltaX < 10 && deltaY < 10)
                    link[0].onLongClick(widget);
            } else if (action == MotionEvent.ACTION_DOWN) {
                Selection.setSelection(buffer,
                        buffer.getSpanStart(link[0]),
                        buffer.getSpanEnd(link[0]));
                lastClickTime = System.currentTimeMillis();
            }
            return true;
        }
    }

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


public static MovementMethod getInstance() {
    if (sInstance == null)
        sInstance = new LongClickLinkMovementMethod();

    return sInstance;
}
    private static LongClickLinkMovementMethod sInstance;
}

Класс LongClickableSpan

import android.text.style.ClickableSpan;
import android.view.View;

public abstract class LongClickableSpan extends ClickableSpan {

    abstract public void onLongClick(View view);
}

Фактическая реализация

LongClickableSpan eruptionText = new LongClickableSpan() {

                                @Override
                                public void onClick(View tvEruptions) {
                                    LinkFunctions.link_eruption_detail(getApplicationContext(),PostErupionID);
                                }

                                @Override
                                public void onLongClick(View tvEruptions) {
                                    if(SignedInUserID != 0) {
                                        DialogFragment newFragment = new Dialogs.QuickActionsDialogFragment();
                                        // Supply num input as an argument.
                                        Bundle args = new Bundle();
                                        args.putLong("eruptionID", PostErupionID);
                                        newFragment.setArguments(args);
                                        newFragment.show(getFragmentManager(), "QuickActions");
                                    }
                                }

                            };
                            ss.setSpan(eruptionText, startpos[(int) j], endpos[(int) j], Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

person wBoekel    schedule 08.11.2014    source источник


Ответы (3)


Я знаю, что этот вопрос старый, и, вероятно, ОП уже решил проблему, но я внес некоторые изменения в исходный метод LongClickLinkMovementMethod, чтобы он срабатывал по истечении времени, а не когда мы отпускаем касание:

import android.os.Handler;
import android.text.Layout;
import android.text.Selection;
import android.text.Spannable;
import android.text.method.LinkMovementMethod;
import android.text.method.MovementMethod;
import android.view.MotionEvent;
import android.widget.TextView;


public class LongClickLinkMovementMethod extends LinkMovementMethod {

    private Handler mLongClickHandler;
    private static int LONG_CLICK_TIME = 1000;
    private boolean mIsLongPressed = false;

    @Override
    public boolean onTouchEvent(final TextView widget, Spannable buffer,
                                MotionEvent event) {
        int action = event.getAction();

        if(action == MotionEvent.ACTION_CANCEL){
            if(mLongClickHandler!=null){
                mLongClickHandler.removeCallbacksAndMessages(null);
            }
        }

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

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

            if (link.length != 0) {
                if (action == MotionEvent.ACTION_UP) {
                    if(mLongClickHandler!=null){
                        mLongClickHandler.removeCallbacksAndMessages(null);
                    }
                    if(!mIsLongPressed) {
                        link[0].onClick(widget);
                    }
                    mIsLongPressed = false;
                } else {
                    Selection.setSelection(buffer,
                            buffer.getSpanStart(link[0]),
                            buffer.getSpanEnd(link[0]));
                    mLongClickHandler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            link[0].onLongClick(widget);
                            mIsLongPressed = true;
                        }
                    },LONG_CLICK_TIME);
                }
                return true;
            }
        }

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


    public static MovementMethod getInstance() {
        if (sInstance == null) {
            sInstance = new LongClickLinkMovementMethod();
            sInstance.mLongClickHandler = new Handler();
        }

        return sInstance;
    }
    private static LongClickLinkMovementMethod sInstance;
}

Таким образом, в основном это использует обработчик для запуска события длинного щелчка через 1000 мс.

person Pedro Oliveira    schedule 03.08.2015
comment
хм, у меня есть longClick и нажмите, когда longclick - person famfamfam; 15.03.2021

Самый простой способ — использовать View.setTag.

Пример кода:

tv.setOnLongClickListener(new OnLongClickListener() {

    @Override
    public boolean onLongClick(View v) {
        Toast.makeText(getApplicationContext(), "onLongClick", Toast.LENGTH_SHORT).show();
        v.setTag("Test");
        return true;
    }
});

private static class NonLongClickableUrlSpan extends URLSpan {

    public NonLongClickableUrlSpan(String url) {
        super(url);
    }

    @Override
    public void onClick(View widget) {
        if (widget.getTag() != null) {
            widget.setTag(null);
            return;
        }
        super.onClick(widget);
    }
}
person kylin17    schedule 26.11.2015

Я отредактировал решение Педро Оливейры с немного обновленным синтаксисом Kotlin:

class LongClickLinkMovementMethod : LinkMovementMethod() {
    private var longClickHandler: Handler? = null
    private var isLongPressed = false
    override fun onTouchEvent(
        widget: TextView, buffer: Spannable,
        event: MotionEvent
    ): Boolean {
        val action = event.action
        if (action == MotionEvent.ACTION_CANCEL) {
            longClickHandler?.removeCallbacksAndMessages(null)
        }
        if (action == MotionEvent.ACTION_UP ||
            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 link = buffer.getSpans(
                off, off,
                LongClickableSpan::class.java
            )
            if (link.isNotEmpty()) {
                if (action == MotionEvent.ACTION_UP) {
                    longClickHandler?.removeCallbacksAndMessages(null)
                    if (!isLongPressed) {
                        link[0].onClick(widget)
                    }
                    isLongPressed = false
                } else {
                    Selection.setSelection(
                        buffer,
                        buffer.getSpanStart(link[0]),
                        buffer.getSpanEnd(link[0])
                    )
                    longClickHandler?.postDelayed({
                        link[0].onLongClick(widget)
                        isLongPressed = true
                    }, LONG_CLICK_TIME)
                }
                return true
            }
        }
        return super.onTouchEvent(widget, buffer, event)
    }

    companion object {
        private const val LONG_CLICK_TIME = 500L
        val instance: MovementMethod?
            get() {
                if (sInstance == null) {
                    sInstance = LongClickLinkMovementMethod()
                    // Handler deprecated https://stackoverflow.com/a/62477706/4116924
                    sInstance!!.longClickHandler = Handler(Looper.getMainLooper())
                }
                return sInstance
            }

        private var sInstance: LongClickLinkMovementMethod? = null
    }
}
person AnT    schedule 13.08.2020