1. 程式人生 > >如何實現多樣式富文字?

如何實現多樣式富文字?

專案中需要使用富文字來顯示訊息通知,由於訊息的型別多達幾十種,且這些不同型別訊息顯示的文案由服務端控制,這裡文案需要使用富文字來顯示不同顏色、大小、字型的文字,所幸是textView支援富文字顯示。具體實現方法有兩種:

一、使用HTML 標記設定樣式

將待顯示字串新增到strings檔案中。例如:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="welcome">Welcome to<b>Android</b>!</string>
</resources>

支援的 HTML 標籤包括:

<a href="...">建立超文字連結

<b>黑體字

<big>字型加大

<blockquote>從兩邊縮排文字

<br>換行插入換行符

<cite>引用,通常是斜體

<dfn>述語定義

<div align="...">用來排版大塊HTML段落,也用於格式化表

<em>強調文字(通常是斜體加黑體)

<font size="..." color="..."face="...">設定字型大小從17,顏色使用名字或RGB的十六進位制值

<h1>

<h6>標題

<i>斜體字

<img src="...">圖片

<p>建立一個段落

<small>字型縮小

<strike>加刪除線

<strong>加重文字(通常是斜體加黑體)

<sub>下標字

<sup>上標字

<tt>打字機風格的字型

<u>下劃線

如果將帶樣式文字資源作為格式字串。 正常情況下是行不通的,因為 String.format(String,Object...) 方法會去除字串中的所有樣式資訊。要解決這個問題只能編寫帶轉義實體的 HTML 標籤,在完成格式設定後,這些實體可通過

fromHtml(String) 恢復。 例如:

1.將您帶樣式的文字資源儲存為HTML 轉義字串:

<resources>
  <string name="welcome_messages">Hello, %1$s! You have &lt;b>%2$d newmessages&lt;/b>.</string>
</resources>

在這個帶格式的字串中,添加了 <b> 元素。請注意,開括號使用 &lt; 表示法進行了 HTML 轉義。

2.然後照常設定字串格式,但還要呼叫 fromHtml(String) 以將HTML 文字轉換成帶樣式文字:

Resources res = getResources();
String text =String.format(res.getString(R.string.welcome_messages), username, mailCount);
CharSequence styledText = Html.fromHtml(text);

由於 fromHtml(String) 方法將設定所有 HTML 實體的格式,因此務必要使用 htmlEncode(String) 對您用於帶格式文字的字串中任何可能的 HTML 字元進行轉義。 例如,如果您向 String.format() 傳遞的字串引數可能包含“<”或“&”之類的字元,則必須在設定格式前進行轉義,這樣在通過 fromHtml(String) 傳遞帶格式字串時,字元就能以原始形式顯示出來。 例如:

String escapedUsername = TextUtil.htmlEncode(username);

Resources res =getResources();
String text =String.format(res.getString(R.string.welcome_messages), escapedUsername, mailCount);
CharSequence styledText = Html.fromHtml(text);

二、使用Spannable 設定樣式

 可以對顏色和字型粗細等屬性進行樣式設定。 首先使用 SpannableStringBuilder 構造文字內容,然後為文字設定 android.text.style 包中定義的樣式,常見的樣式有StrikethroughSpan、StyleSpan、ForegroundColorSpan等。例如,為某段文字內容加上帶顏色和刪除線的粗體樣式。

public CharSequence renderSpan(Stringtext, String color, boolean isBold, boolean isDelete) {

        if(TextUtils.isEmpty(color)) {

            color ="#272934";//預設值

        }

        if(TextUtils.isEmpty(text)) {

            return null;

        }

       SpannableStringBuilder span = new SpannableStringBuilder();

       span.append(text);

        if(isDelete) {

            StrikethroughSpanstrikethroughSpan = new StrikethroughSpan();

            span.setSpan(strikethroughSpan,0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

        }

        if (isBold){

            StyleSpanboldStyle = new StyleSpan(Typeface.BOLD);

            span.setSpan(boldStyle,0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

        }

        span.setSpan(newForegroundColorSpan(Color.parseColor(color)), 0,text.length(),Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

        returnspan;

}

最後,專案中用到了格式化字串,所以只能採取第一種方式來避免樣式資訊被清除。這裡遇到一個非常奇葩的坑, fromHtml(String)無法正常顯示帶<strike>標籤的格式。解決辦法是結合使用spannable,如下:

 public CharSequence renderSpan(String text,String color, boolean isBold, boolean isDelete) {

        if(TextUtils.isEmpty(color)) {

            color ="#272934";

        }

        if(TextUtils.isEmpty(text)) {

            returnspan;

        }

       SpannableStringBuilder span = new SpannableStringBuilder();

       span.append(text);

        if(isDelete) {

           span.insert(0, "<strike>");

           span.append("</strike>");

        }

        if (isBold){

           span.insert(0, "<b>");

           span.append("</b>");

        }

       //span.insert(0, "<font color=\"" + color +"\">");

       //span.append("</font>");

        returnspan;

    }

Resources res = getResources();
String text = String.format(res.getString(R.string.welcome_messages),renderSpan(escapedUsername ,"",true,true));

SpannableStringBuilder operateStr =new  SpannableStringBuilder(text);

        Object[]spans = operateStr.getSpans(0, operateStr.length(), Object.class);

        if (spans.length > 0) {

            for(Object object : spans) {

                intstart = operateStr.getSpanStart(object);

                intend = operateStr.getSpanEnd(object);

               StrikethroughSpan strikethroughSpan = new StrikethroughSpan();

               operateStr.setSpan(strikethroughSpan, start, end,Spanned.SPAN_INCLUSIVE_EXCLUSIVE);

               break;

            }

        }

這裡通過其他span物件來確定樣式字串的位置,然後採用第二種方式進行處理。