解決ListView裏TextView設置LinkMovementMethod後導致其ItemClick失效的問題

最近在做項目研發過程中有這樣一個需求:ListView的Item裏的子控件TextView要設置超鏈接、指定文字高亮顯示,然後點擊超鏈接後跳轉到指定URL的網頁。實現超鏈接的跳轉這很容易,只要通過對TextView設置SpannableString對象即可,即如下代碼:

TextView tv = (TextView)findViewById(R.id.tv);
SpannableString sp = new SpannableString("此處爲tv裏顯示的內容");
sp.setSpan( new  URLSpan( "http://www.baidu.com" ), 3 ,  8 , Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.setText(sp);
tv.setMovementMethod(LinkMovementMethod.getInstance());

通過這樣的設置後已經能夠實現對超鏈接點擊跳轉到指定URL的網頁了,可麻煩又來了,你會發現點擊ListView裏的Item時沒有任何反應,這是什麼原因呢?還記得上面在設置超鏈接的時候有這樣一條語句:tv.setMovementMethod(LinkMovementMethod.getInstance());我們現在把這條語句註釋掉看看……run App,結果點擊Item的時候能夠響應了,可惜超鏈接又失效了,任你點擊也沒有響應了,哎,真可謂是“魚和熊掌不可兼得”。現在已經斷定Item失效的原因何在了,那爲什麼這條語句就會導致Item點擊失效呢?源碼往往是揭開程序中各種奇芭問題的尖銳利器,讓我們跟蹤下源碼吧……打開TextView的源碼文件,截取的關鍵代碼片段如下:

wKioL1LHkTyjKLGQAACZ9Ux9MIg927.jpg

該代碼片段是TextView源碼的第1421行(Android4.2.2版本),我們發現不能通過重寫此方法來解決我們所面臨的問題,再繼續跟蹤LinkMovementMethod這個類吧,關鍵源碼如下:

  @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);
        //獲取textview裏的超鏈接對象,並用ClickableSpan數組盛裝
        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; //處理結束後返回true,這裏一定要注意:當返回值爲true時則表示點擊事件已經被,就再也不會繼續傳遞了
        } else {
            Selection.removeSelection(buffer);
        }
    }
    return super.onTouchEvent(widget, buffer, event);
}

上述源碼爲LinkMovementMethod類的第188行。發現了Item點擊失效的原因是因爲onTouch方法總是返回true而並沒有根據不同的情況來作處理,此時大家可能會想直接對這個方法重寫就能解決問題了。我和大家想的也一樣,對該方法重寫,並根據情況返回true或false,遺憾的是還是沒有效果,並且在重寫的方法裏看不到輸出的日誌信息,暫時不明其中原因,請高手賜教!眼看就要看到光明瞭,可還是被打擊了……不要灰心,麪包總是會有的,如果你不放棄的話,哈哈。換個keywords google一下,終於找到國外的一個網站,上面的文章標題是:

wKiom1LHlTzxAlYtAAA2uld9Jrk531.jpg

此時此刻的心情真是如獲至寶呀……接着看下去……發現有高人是這樣解決的:

wKioL1LHldywWR1tAAE4WGfZtn4031.jpg

發現這位高人本質思路是我們開始分析的本質思路一樣,只不過他把要處理的代碼放在了TextView的onTouch方法裏,然後根據不同的情況返回true或false.在getView()方法裏對相應的TextView進行設置吧,Run app……見證奇蹟的時刻到了……哈哈,結果真的能行了,耶哦!

原文鏈接:http://stackoverflow.com/questions/8558732/listview-textview-with-linkmovementmethod-makes-list-item-unclickable

經過此劫,我發現了爲什麼國外的技術總是比國內要先進得多了,我在此並不是貶低同僚,不支持國產,而是在國內的技術普遍都是你抄我,我抄你的,有的甚至連原文鏈接都不放……大家可以看看國外這個技術網站人家是怎麼解決問題的,真是按部就班,循序漸進的,不僅讓你知其然還知其所以然。

歡迎加入QQ討論羣:285077071

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章