关于Textview的ClickSpan和自身点击事件冲突

TextView设置SpanableString后,假如有ClickSpan的话,还需要设置Movemethod才能正确响应点击事件。
假如TextView有ClickSpan并且自身还有点击响应的话,那么只会响应ClickSpan,而自身的点击事件则不会响应。

方案1,给TextView设置TouchListener,模拟MoveMethod的方式:

public class LinkMovementMethodOverride  implements View.OnTouchListener{

    //回调 点击TextView非clickspan的地方的回调
    private ForumItemLinkedMethod.IClickNoSpan mIClickNoSpan;

    public LinkMovementMethodOverride(ForumItemLinkedMethod.IClickNoSpan IClickNoSpan) {
        mIClickNoSpan = IClickNoSpan;
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        TextView widget = (TextView) v;
        CharSequence text = widget.getText();
        try {
            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);
                float lineRight = layout.getLineRight(line);
                int off = layout.getOffsetForHorizontal(line, x);

                boolean moreThentextEnd = (x-lineRight)>20;//点击位置超过行末太远

                ClickableSpan[] link = getSpans(text,off);

                if (!moreThentextEnd&&link.length != 0) {
                    if (action == MotionEvent.ACTION_UP) {
                        link[0].onClick(widget);
                    } else if (action == MotionEvent.ACTION_DOWN) {
                    }

                    return true;
                } else {

                    if (action == MotionEvent.ACTION_UP) {
                        if(mIClickNoSpan!=null){
                            try {
                                mIClickNoSpan.onClickNoSpan();
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }
                    return true;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    //根据SpannedString 或者SpannableString(注意这俩不一样), 获取指定位置的span
    private ClickableSpan[] getSpans(CharSequence text,int off) throws Exception {
        if(text instanceof SpannedString){
            SpannedString buffer = (SpannedString) text;
            return buffer.getSpans(off, off, ClickableSpan.class);
        }else if(text instanceof SpannableString){
            SpannableString buffer = (SpannableString) text;
            return buffer.getSpans(off, off, ClickableSpan.class);
        }else{
            throw new RuntimeException("hans:not support text");
        }
    }

}

关键代码:

//1.修正坐标
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();

x += widget.getScrollX();
y += widget.getScrollY();              

then:

//获取xy坐标在文字里的offset
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y);
float lineRight = layout.getLineRight(line);
int off = layout.getOffsetForHorizontal(line, x);

then:
获取指定位置的span,判断是不是Clickspan。。。

方案2:自定义LinkMoveMethod,貌似有时候没用,参考吧

public class ForumItemLinkedMethod extends LinkMovementMethod {

    public interface IClickNoSpan{
        void onClickNoSpan();
    }

    private IClickNoSpan mIClickNoSpan;

    public ForumItemLinkedMethod(IClickNoSpan IClickNoSpan) {
        mIClickNoSpan = IClickNoSpan;
    }

    @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);
            float lineRight = layout.getLineRight(line);
            boolean moreThentextEnd = (x-lineRight)>20;
            int off = layout.getOffsetForHorizontal(line, x);

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

            if (!moreThentextEnd&&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 {
                Selection.removeSelection(buffer);

                if (action == MotionEvent.ACTION_UP) {
                    if(mIClickNoSpan!=null){
                        try {
                            mIClickNoSpan.onClickNoSpan();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
                return true;
            }
        }
        return Touch.onTouchEvent(widget, buffer, event);
    }
}

使用:
textContent.setMovementMethod(new ForumItemLinkedMethod());

你可能感兴趣的:(关于Textview的ClickSpan和自身点击事件冲突)