如何實作Android文字(TextView)裡的超連結onClick監聽與排版

最近寫了比較多關於TextView的東西,才發現Android的TextView其實功能很強大,不是只有單純的文字格式,換換字型、改粗體、斜體、行距這些基本款,更可以使用Html的語法來做文字排版。

如果要使用Html做為TextView的排版方法如下:

1.將Html格式的文字放在Resource的String裡,並且在html格式的文字前後各加上了<![CDATA[]]>
<string name="html">
        <![CDATA[
        <b><a href="https://www.youtube.com/watch?v=6xc3dHjPje0">說好的幸福呢</a></b>
        <br>
        作詞:方文山<br>
        作曲:周杰倫<br>
        <br>
        妳的回話凌亂著 在這個時刻<br>
        我想起噴泉旁的白鴿 甜蜜散落了<br>
        <br>
        情緒莫名的拉扯 我還愛妳呢<br>
        而妳斷斷續續唱著歌 假裝沒事了<br>
        <br>
        時間過了 走了 愛情面臨選擇 妳冷了 倦了 我哭了<br>
        離開時的不快樂 妳用卡片手寫著 有些愛只給到這 真的痛了<br>
        怎麼了 妳累了 說好的 幸福呢<br>
        我懂了 不說了 愛淡了 夢遠了<br>
        開心與不開心一一細數著 妳再不捨<br>
        那些愛過的感覺都太深刻 我都還記得<br>
        <br>
        妳不等了 說好的 幸福呢<br>
        我錯了 淚乾了 放手了 後悔了<br>
        只是回憶的音樂盒還旋轉著 要怎麼停呢<br>
        ]]>
</string>

2.將文字轉為Html格式
textView.setText(Html.fromHtml(getString(R.string.html));

基本上到第二步就已經可以呈現Html樣式的文字了,但是如果要讓文字裡面的超連結要能夠點擊使用瀏覽器開啟,就要改為使用下面的語法
Spanned sp = Html.fromHtml(getString(R.string.html));
textView.setText(sp);
textView.setMovementMethod(LinkMovementMethod.getInstance());

於是你會發現點選歌名「說好的幸福呢」就自動開啟瀏覽器外連到youtube的影片

但是如果不要開啟瀏覽器外連出去呢?
能不能利用文字裡的超連結去執行某段程式碼、某個Method呢?
而且文字裡面的超連結不限定只有一個,有辦法點擊到不同的超連結就執行不同的Method嗎?

答案是可以的

一樣以上面的歌詞為例,需求是點擊了方文山與周杰倫就會分別彈出Toast訊息顯示「你點選了:方文山」與「你點選了:周杰倫」,實作的方法如下:

1.先將超連結自行定義,假設周杰倫的超連結為1、方文山的超連結為2,改寫如下:
<string name="html">
        <![CDATA[
        <b><a href="https://www.youtube.com/watch?v=6xc3dHjPje0">說好的幸福呢</a></b>
        <br>
        作詞:<a href="2">方文山</a><br>
        作曲:<a href="1">周杰倫</a><br>
        <br>
        妳的回話凌亂著 在這個時刻<br>
        我想起噴泉旁的白鴿 甜蜜散落了<br>
        <br>
        情緒莫名的拉扯 我還愛妳呢<br>
        而妳斷斷續續唱著歌 假裝沒事了<br>
        <br>
        時間過了 走了 愛情面臨選擇 妳冷了 倦了 我哭了<br>
        離開時的不快樂 妳用卡片手寫著 有些愛只給到這 真的痛了<br>
        怎麼了 妳累了 說好的 幸福呢<br>
        我懂了 不說了 愛淡了 夢遠了<br>
        開心與不開心一一細數著 妳再不捨<br>
        那些愛過的感覺都太深刻 我都還記得<br>
        <br>
        妳不等了 說好的 幸福呢<br>
        我錯了 淚乾了 放手了 後悔了<br>
        只是回憶的音樂盒還旋轉著 要怎麼停呢<br>
        ]]>
</string>

2.將文字設定為超連結可以具有點擊效果
Spanned sp = Html.fromHtml(getString(R.string.html));
textView.setText(sp);
textView.setMovementMethod(LinkMovementMethod.getInstance());

這時候會發現如果按下了周杰倫與方文山超連結還不會產生任何效果,但在Log會發現下列的警告訊息:
(意思是我收到了一個名為1的東西,但因為沒有任何事先定義的schema,所以不知道該怎麼執行)
URLSpan: Actvity was not found for intent, Intent { act=android.intent.action.VIEW dat=1 (has extras) }

3.繼續接著製作文字超連結onClick監聽
/**
* 文字超連結onClick監聽
*/
private class CustomTextClick extends ClickableSpan {
    private String mUrl;

    CustomerTextClick(String url) {
        mUrl = url;
    }

    @Override
    public void onClick(View widget) {

        if (mUrl.equals("1")) {
            Toast.makeText(context, "你點選了:周杰倫", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(context, "你點選了:方文山", Toast.LENGTH_SHORT).show();
        }
    }
}
4.設定文字超連結監聽
/**
* 設定文字超連結監聽
*
* @param textView
* @param sp
*/
private void setTextHyperLinkListener(TextView textView, Spanned sp) {
    CharSequence text = textView.getText();
    if (text instanceof Spannable) {
        int end = text.length();
        URLSpan[] urls = sp.getSpans(0, end, URLSpan.class);
        SpannableStringBuilder style = new SpannableStringBuilder(text);
        style.clearSpans();

        for (URLSpan url : urls) {
            CustomTextClick click = new CustomTextClick(url.getURL());
            style.setSpan(click, sp.getSpanStart(url), sp.getSpanEnd(url),
                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        }

        textView.setText(style);
    }
}

於是警告訊息不見了,文字裡也可以偵測到所點擊的URL來做為切換執行不同Method的方法,所以在這邊會用數字做為超連結也是方便日後可以使用字串轉整數,就能使用switch case去做更多Method的切換執行。

Reference:
http://stackoverflow.com/questions/2116162/how-to-display-html-in-textview
https://stackoverflow.com/questions/19750458/android-clickablespan-get-text-onclick

留言

這個網誌中的熱門文章

Mac安裝JDK後仍出現沒有runtime的錯誤 No Java runtime present, requesting install

Android使用Callback做為傳遞資料/通知的方法

如何實作從API抓取資料顯示在列表頁(ListView)上