textview 显示html方法解析

时间:2023-03-09 03:12:20
textview 显示html方法解析

现在网络的繁盛时代,光文字是不能满足人们的胃口的,图片,flash,音频,视频就成为浏览网页的主流显示,在手机上也一样。在手机上显示从网络端获取的数据显示,大家很自然的想起两种方式,一种就是webview,一种就是TextView。当然webView直接显示html页面就行了,我主要说的TextView显示html内容。 
首先,说下TextView到底支持那些标签呢,通过对源码的查看,发现Textview可以解析一部分html标签,如:

复制代码代码如下:
<a href="..."> 
<b> 
<big> 
<blockquote> 
<br> 
<cite> 
<dfn> 
<div align="..."> 
<em> 
<font size="..." color="..." face="..."> 
<h1> 
<h2> 
<h3> 
<h4> 
<h5> 
<h6> 
<i> 
<img src="..."> 
<p> 
<small> 
<strike> 
<strong> 
<sub> 
<sup> 
<tt> 
<u> 

大家想究其根本可以查看android.text.Html源码,其中有一段这样写:

复制代码代码如下:
private void handleStartTag(String tag, Attributes attributes) { 
if (tag.equalsIgnoreCase("br")) { 
// We don't need to handle this. TagSoup will ensure that there's a </br> for each <br> 
// so we can safely emite the linebreaks when we handle the close tag. 
} else if (tag.equalsIgnoreCase("p")) { 
handleP(mSpannableStringBuilder); 
} else if (tag.equalsIgnoreCase("div")) { 
handleP(mSpannableStringBuilder); 
} else if (tag.equalsIgnoreCase("em")) { 
start(mSpannableStringBuilder, new Bold()); 
} else if (tag.equalsIgnoreCase("b")) { 
start(mSpannableStringBuilder, new Bold()); 
} else if (tag.equalsIgnoreCase("strong")) { 
start(mSpannableStringBuilder, new Italic()); 
} else if (tag.equalsIgnoreCase("cite")) { 
start(mSpannableStringBuilder, new Italic()); 
} else if (tag.equalsIgnoreCase("dfn")) { 
start(mSpannableStringBuilder, new Italic()); 
} else if (tag.equalsIgnoreCase("i")) { 
start(mSpannableStringBuilder, new Italic()); 
} else if (tag.equalsIgnoreCase("big")) { 
start(mSpannableStringBuilder, new Big()); 
} else if (tag.equalsIgnoreCase("small")) { 
start(mSpannableStringBuilder, new Small()); 
} else if (tag.equalsIgnoreCase("font")) { 
startFont(mSpannableStringBuilder, attributes); 
} else if (tag.equalsIgnoreCase("blockquote")) { 
handleP(mSpannableStringBuilder); 
start(mSpannableStringBuilder, new Blockquote()); 
} else if (tag.equalsIgnoreCase("tt")) { 
start(mSpannableStringBuilder, new Monospace()); 
} else if (tag.equalsIgnoreCase("a")) { 
startA(mSpannableStringBuilder, attributes); 
} else if (tag.equalsIgnoreCase("u")) { 
start(mSpannableStringBuilder, new Underline()); 
} else if (tag.equalsIgnoreCase("sup")) { 
start(mSpannableStringBuilder, new Super()); 
} else if (tag.equalsIgnoreCase("sub")) { 
start(mSpannableStringBuilder, new Sub()); 
} else if (tag.length() == 2 && 
Character.toLowerCase(tag.charAt(0)) == 'h' && 
tag.charAt(1) >= '1' && tag.charAt(1) <= '6') { 
handleP(mSpannableStringBuilder); 
start(mSpannableStringBuilder, new Header(tag.charAt(1) - '1')); 
} else if (tag.equalsIgnoreCase("img")) { 
startImg(mSpannableStringBuilder, attributes, mImageGetter); 
} else if (mTagHandler != null) { 
mTagHandler.handleTag(true, tag, mSpannableStringBuilder, mReader); 


private void handleEndTag(String tag) { 
if (tag.equalsIgnoreCase("br")) { 
handleBr(mSpannableStringBuilder); 
} else if (tag.equalsIgnoreCase("p")) { 
handleP(mSpannableStringBuilder); 
} else if (tag.equalsIgnoreCase("div")) { 
handleP(mSpannableStringBuilder); 
} else if (tag.equalsIgnoreCase("em")) { 
end(mSpannableStringBuilder, Bold.class, new StyleSpan(Typeface.BOLD)); 
} else if (tag.equalsIgnoreCase("b")) { 
end(mSpannableStringBuilder, Bold.class, new StyleSpan(Typeface.BOLD)); 
} else if (tag.equalsIgnoreCase("strong")) { 
end(mSpannableStringBuilder, Italic.class, new StyleSpan(Typeface.ITALIC)); 
} else if (tag.equalsIgnoreCase("cite")) { 
end(mSpannableStringBuilder, Italic.class, new StyleSpan(Typeface.ITALIC)); 
} else if (tag.equalsIgnoreCase("dfn")) { 
end(mSpannableStringBuilder, Italic.class, new StyleSpan(Typeface.ITALIC)); 
} else if (tag.equalsIgnoreCase("i")) { 
end(mSpannableStringBuilder, Italic.class, new StyleSpan(Typeface.ITALIC)); 
} else if (tag.equalsIgnoreCase("big")) { 
end(mSpannableStringBuilder, Big.class, new RelativeSizeSpan(1.25f)); 
} else if (tag.equalsIgnoreCase("small")) { 
end(mSpannableStringBuilder, Small.class, new RelativeSizeSpan(0.8f)); 
} else if (tag.equalsIgnoreCase("font")) { 
endFont(mSpannableStringBuilder); 
} else if (tag.equalsIgnoreCase("blockquote")) { 
handleP(mSpannableStringBuilder); 
end(mSpannableStringBuilder, Blockquote.class, new QuoteSpan()); 
} else if (tag.equalsIgnoreCase("tt")) { 
end(mSpannableStringBuilder, Monospace.class, 
new TypefaceSpan("monospace")); 
} else if (tag.equalsIgnoreCase("a")) { 
endA(mSpannableStringBuilder); 
} else if (tag.equalsIgnoreCase("u")) { 
end(mSpannableStringBuilder, Underline.class, new UnderlineSpan()); 
} else if (tag.equalsIgnoreCase("sup")) { 
end(mSpannableStringBuilder, Super.class, new SuperscriptSpan()); 
} else if (tag.equalsIgnoreCase("sub")) { 
end(mSpannableStringBuilder, Sub.class, new SubscriptSpan()); 
} else if (tag.length() == 2 && 
Character.toLowerCase(tag.charAt(0)) == 'h' && 
tag.charAt(1) >= '1' && tag.charAt(1) <= '6') { 
handleP(mSpannableStringBuilder); 
endHeader(mSpannableStringBuilder); 
} else if (mTagHandler != null) { 
mTagHandler.handleTag(false, tag, mSpannableStringBuilder, mReader); 

通过源码可以看到,除了默认的一些标签,其还支持自定义标签;看下面代码: 
else if (mTagHandler != null) { 
mTagHandler.handleTag(false, tag, mSpannableStringBuilder, mReader); 

系统会调用mTagHandler的handleTag方法。所以,我们可以实现此接口,来解析自己定义的标签类型。 
具体的,自己可以看一下下面实例:

复制代码代码如下:
package com.mxgsa.tvimg; 
import org.xml.sax.XMLReader; 
import android.content.Context; 
import android.content.Intent; 
import android.text.Editable; 
import android.text.Html.TagHandler; 
import android.text.Spanned; 
import android.text.style.ClickableSpan; 
import android.view.View; 
import android.view.View.OnClickListener; 
public class MxgsaTagHandler implements TagHandler{ 
private int sIndex = 0; 
private int eIndex=0; 
private final Context mContext; 
public MxgsaTagHandler(Context context){ 
mContext=context; 

public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) { 
// TODO Auto-generated method stub 
if (tag.toLowerCase().equals("mxgsa")) { 
if (opening) { 
sIndex=output.length(); 
}else { 
eIndex=output.length(); 
output.setSpan(new MxgsaSpan(), sIndex, eIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 



private class MxgsaSpan extends ClickableSpan implements OnClickListener{ 
@Override 
public void onClick(View widget) { 
// TODO Auto-generated method stub 
//具体代码,可以是跳转页面,可以是弹出对话框,下面是跳转页面 
mContext.startActivity(new Intent(mContext,MainActivity.class)); 


调用页面:

复制代码代码如下:
package com.mxgsa.tvimg; 
import android.app.Activity; 
import android.os.Bundle; 
import android.text.Html; 
import android.text.method.LinkMovementMethod; 
import android.widget.TextView; 
public class MxgsaActivity extends Activity{ 
private TextView tView; 
@Override 
public void onCreate(Bundle savedInstanceState) { 
super.onCreate(savedInstanceState); 
setContentView(R.layout.mxgsa_activity); 
findControl(); 
setData(); 

private void findControl() { 
tView = (TextView) findViewById(R.id.tvImage); 

private void setData() { 
// TODO Auto-generated method stub 
final String sText = "测试自定义标签:<br><h1><mxgsa>测试自定义标签</mxgsa></h1>"; 
tView.setText(Html.fromHtml(sText, null, new MxgsaTagHandler(this))); 
tView.setClickable(true); 
tView.setMovementMethod(LinkMovementMethod.getInstance());