Andoid TextView显示富文本html内容及问题处理
目錄
- 富文本內容與效果
- TextView + Html
- ImageGetter 處理圖片(表情)
- TagHandler 處理html內容的節點
- Html的轉換過程
- HtmlToSpannedConverter
- handleStartTag
- startCssStyle(mSpannableStringBuilder, attributes)字體無效果實現
- getForegroundColorPattern顏色不顯示的坑
- 處理辦法
- 顏色修改
- 粗體支持
- 斜體支持
來了來了,
html頁面內容不是用用webview的嗎,TextView顯示html什么鬼?
老鐵莫急,沒錯,html頁面內容多數情況下都是用webview來顯示的,尤其是app里面常見的"關于"、“隱私政策”等,這都是單一的顯示,或者整個頁面就顯示這么一個page頁面,自然也就選擇webview。
當遇到富文本這樣的html內容片段,而且是以列表方式顯示多段內容不一樣的內容時候,怎么辦呢。基于源生的習慣,自然就是TextView + Html了。
有坑,但問題不大。
富文本內容與效果
如下一段html,粗體、斜體、橘色和帶了一個表情:
<SPAN style="FONT-SIZE: 10pt; FONT-WEIGHT: bold; COLOR: #ff8000; FONT-STYLE: italic">hello<IMG src="emotion\emotion.rb.gif" thePath custom="false">boy </SPAN>效果:
TextView + Html
TextView 就不介紹了,主要介紹Html這個類。
Html.java在android.text這個package下,包名也就看出是和文字相關的類。其核心本質是解析html內容,根據html的style給構造出Spanned,Spanned又是什么東西?Spanned是CharSequence的孩子。
平常給TextView設置文字 setText(CharSequence text)這個函數的參數就是CharSequence ,只不過實際傳遞的是CharSequence 的另外一個孩子String。
Html.java 提供html內容和Spanned的相互轉換:
html->Spanned:
public static Spanned fromHtml(String source, int flags)
public static Spanned fromHtml(String source, int flags, ImageGetter imageGetter,TagHandler tagHandler)
Spanned->html:
public static String toHtml(Spanned text, int option)
但實際上上述內容出表情外,其他的效果完全沒有,包括顏色。具體請往后看
ImageGetter 處理圖片(表情)
當遇到<img>標簽的時候就會回調, 對應的返回一個Drawable對象。source 參數就是<img>的src屬性的內容,也就是圖片路徑。根據上文給出的內容,這里source是“emotion\emotion.rb.gif”。同時注意返回的Drawable對象一定要給定邊界,也就是drawable.setBounds(),不然不會顯示圖片。如果這里返回一個null,一般出現一個小矩形。
/*** Retrieves images for HTML <img> tags.*/public static interface ImageGetter {/*** This method is called when the HTML parser encounters an* <img> tag. The <code>source</code> argument is the* string from the "src" attribute; the return value should be* a Drawable representation of the image or <code>null</code>* for a generic replacement image. Make sure you call* setBounds() on your Drawable if it doesn't already have* its bounds set.*/public Drawable getDrawable(String source);}TagHandler 處理html內容的節點
這個標簽捕獲是有條件的,如果html內容的標簽沒有在Html中定義捕才回調出來,在顯示效果上是沒效的,需要自行處理這個標簽,對應的編輯output。
/*** Is notified when HTML tags are encountered that the parser does* not know how to interpret.*/public static interface TagHandler {/*** This method will be called whenn the HTML parser encounters* a tag that it does not know how to interpret.*/public void handleTag(boolean opening, String tag,Editable output, XMLReader xmlReader);}注釋講的清楚,parser 識別不了的就會回調通知。
Html的轉換過程
從fromHtml入口可以看出,是HtmlToSpannedConverter 在工作,執行convert
public static Spanned fromHtml(String source, int flags, ImageGetter imageGetter,TagHandler tagHandler) {Parser parser = new Parser();try {parser.setProperty(Parser.schemaProperty, HtmlParser.schema);} catch (org.xml.sax.SAXNotRecognizedException e) {// Should not happen.throw new RuntimeException(e);} catch (org.xml.sax.SAXNotSupportedException e) {// Should not happen.throw new RuntimeException(e);}HtmlToSpannedConverter converter =new HtmlToSpannedConverter(source, imageGetter, tagHandler, parser, flags);return converter.convert();}HtmlToSpannedConverter
從代碼上看HtmlToSpannedConverter 還不是內部類,是和Html平行定義的。且實現了ContentHandler,ContentHandler就是xml解析回調接口,而該類主要處理了3個回調,其余空實現:
public void startElement(String uri, String localName, String qName, Attributes attributes)throws SAXException {handleStartTag(localName, attributes);}public void endElement(String uri, String localName, String qName) throws SAXException {handleEndTag(localName);}public void characters(char ch[], int start, int length) throws SAXException {StringBuilder sb = new StringBuilder();/** Ignore whitespace that immediately follows other whitespace;* newlines count as spaces.*/for (int i = 0; i < length; i++) {char c = ch[i + start];if (c == ' ' || c == '\n') {char pred;int len = sb.length();if (len == 0) {len = mSpannableStringBuilder.length();if (len == 0) {pred = '\n';} else {pred = mSpannableStringBuilder.charAt(len - 1);}} else {pred = sb.charAt(len - 1);}if (pred != ' ' && pred != '\n') {sb.append(' ');}} else {sb.append(c);}}mSpannableStringBuilder.append(sb);}當開始一個標簽時調用 handleStartTag
結束一個標簽時調用handleEndTag
解析到文本的時候就追加到mSpannableStringBuilder中
handleStartTag
這里能看出Html類處理了多少標簽,同時也應證沒有定義的標簽都拋給外部處理
注意這里標簽的匹配不區分大小寫 (equalsIgnoreCase)
明明<SPAN> 是被解析的(tag.equalsIgnoreCase(“span”),就是沒有顏色和粗體、斜體呢?再看startCssStyle(mSpannableStringBuilder, attributes)
startCssStyle(mSpannableStringBuilder, attributes)字體無效果實現
private void startCssStyle(Editable text, Attributes attributes) {String style = attributes.getValue("", "style");if (style != null) {Matcher m = getForegroundColorPattern().matcher(style);if (m.find()) {int c = getHtmlColor(m.group(1));if (c != -1) {start(text, new Foreground(c | 0xFF000000));}}m = getBackgroundColorPattern().matcher(style);if (m.find()) {int c = getHtmlColor(m.group(1));if (c != -1) {start(text, new Background(c | 0xFF000000));}}m = getTextDecorationPattern().matcher(style);if (m.find()) {String textDecoration = m.group(1);if (textDecoration.equalsIgnoreCase("line-through")) {start(text, new Strikethrough());}}}}取出style 屬性,且此處指處理顏色,并沒有處理字體,字體肯定是不會有效果的了。接著看getForegroundColorPattern。
getForegroundColorPattern顏色不顯示的坑
再看取屬性里面的顏色是通過正則表達式來取的,前景色正則表達式: “(?:\s+|\A)color\s*:\s*(\S*)\b”)
private static Pattern getForegroundColorPattern() {if (sForegroundColorPattern == null) {sForegroundColorPattern = Pattern.compile("(?:\\s+|\\A)color\\s*:\\s*(\\S*)\\b");}return sForegroundColorPattern;}這里是個坑,color是小寫,內容中的是COLOR,沒有匹配到顏色。同時背景色也是小寫的color。
處理辦法
調用還是不變,但要對原始內容進行修改
顏色修改
直接將style 屬性的值修改為小寫
<!--這樣就可以顯示顏色了--> <SPAN style="font-size: 10pt; font-weight: bold; color: #ff8000; font-style: italic">hello<IMG src="emotion\emotion.rb.gif" thePath custom="false">boy</SPAN>粗體支持
從代碼上看是明確不處理style 屬性中的粗體,但從handleStartTag解析中有如下片段
else if (tag.equalsIgnoreCase("strong")) {start(mSpannableStringBuilder, new Bold());} else if (tag.equalsIgnoreCase("b")) {start(mSpannableStringBuilder, new Bold());}基于這個片段,判斷style中屬性中的font-weight如果是bold值,那么直接在原內容基礎上包裹標簽<strong>或<b>。
具體如下:
斜體支持
思路和粗體一樣,選擇多一點
代碼片段:
基于這個片段,判斷style中屬性中的font-style如果是italic值,那么直接在原內容基礎上包裹標簽<em>,<cite>,<dfn>,<i>之一
具體如下:
至此,這段html的顏色、粗體、斜體都能顯示了。
總結
以上是生活随笔為你收集整理的Andoid TextView显示富文本html内容及问题处理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python参数检验框架_基于pytho
- 下一篇: 上海交通大学计算机应用基础答案,西安交通