如何實現多樣式富文字?
專案中需要使用富文字來顯示訊息通知,由於訊息的型別多達幾十種,且這些不同型別訊息顯示的文案由服務端控制,這裡文案需要使用富文字來顯示不同顏色、大小、字型的文字,所幸是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="...">設定字型大小從1到7,顏色使用名字或RGB的十六進位制值
<h1>
<i>斜體字
<img src="...">圖片
<p>建立一個段落
<small>字型縮小
<strike>加刪除線
<strong>加重文字(通常是斜體加黑體)
<sub>下標字
<sup>上標字
<tt>打字機風格的字型
<u>下劃線
如果將帶樣式文字資源作為格式字串。 正常情況下是行不通的,因為 String.format(String,Object...) 方法會去除字串中的所有樣式資訊。要解決這個問題只能編寫帶轉義實體的
HTML 標籤,在完成格式設定後,這些實體可通過
1.將您帶樣式的文字資源儲存為HTML 轉義字串:
<resources>
<string name="welcome_messages">Hello, %1$s! You have <b>%2$d newmessages</b>.</string>
</resources>
在這個帶格式的字串中,添加了 <b> 元素。請注意,開括號使用 < 表示法進行了 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物件來確定樣式字串的位置,然後採用第二種方式進行處理。