關于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());

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,886評論 18 139
  • 姓名 連嘉瑋 學號 16040120089 轉自:http://www.lxweimin.com/p/b5fb515...
    連嘉瑋閱讀 1,360評論 1 0
  • 在iOS開發中經常會涉及到觸摸事件。本想自己總結一下,但是遇到了這篇文章,感覺總結的已經很到位,特此轉載。作者:L...
    WQ_UESTC閱讀 6,107評論 4 26
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,124評論 25 708
  • ¥開啟¥ 【iAPP實現進入界面執行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個線程,因...
    小菜c閱讀 6,510評論 0 17