在项目中有时需要显示一些Html文本,但是时webView的性能和效率都不太好,所以就需要使用Textview来显示Html文本,好在Andriod本身提供了一个简单的Html解析的方法:
Html.fromHtml(text, ImageGetter, TagHandler);
下面是通过重写TextView的方式实现自动解析Html文本的自定义组件HtmlView,该组件主要实现的功能是解析<img/>标签显示图片并添加图片的点击事件,另外在代码中也示范了一种解析自定义标签的方法(此方法参考stackoverflow上某个问题解答);例子程序在最后,下面是核心代码:
/** * Sets the text that this TextView is to display (see * {@link #setText(CharSequence)}) and also sets whether it is stored * in a styleable/spannable buffer and whether it is editable. * * @param text * @param type * @attr ref android.R.styleable#TextView_text * @attr ref android.R.styleable#TextView_bufferType */ @Override public void setText(CharSequence text, BufferType type) { if(null == text){ this.mText = ""; }else{ this.mText = text; } this.mText = text; Spanned spanned = Html.fromHtml(this.mText.toString(), new MyImageGetter(), new MyTagHandler()); super.setText(spanned, type); } @Override public boolean isClickable() { return true; } @Override protected MovementMethod getDefaultMovementMethod() { return LinkMovementMethod.getInstance(); } class MyImageGetter implements Html.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. * * @param source */ @Override public Drawable getDrawable(String source) { /*在这里根据source来加载图片,并返回*/ /*简单测试,返回程序ic_lanucher*/ /*网络图片需要异步加载,在此处发起异步加载线程,图片加载完成后再设置一次setText, 当再次执行到此处时,将加载好的图片(应存放在缓存中)返回就行了*/ Drawable drawable = null; if(Build.VERSION.SDK_INT < 21){ drawable = getResources().getDrawable(R.mipmap.ic_launcher); drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); }else{ drawable = getResources().getDrawable(R.mipmap.ic_launcher, null); drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); } return drawable; } } /** * 用来通知当解析器遇到无法识别的标签时该作出何种处理 */ class MyTagHandler implements Html.TagHandler{ /** * 参数: * opening:为true时表示某个标签开始解析,为false时表示该标签解析完 * tag:当前解析的标签 * output:文本中的内容 * xmlReader:xml解析器 */ @Override public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) { Log.e("TAG-->", tag); Log.e("output-->", output.toString()); if (tag.toLowerCase().equals("img")) {//解析<img/>标签(注意标签格式不是<img></img>) Log.e("opening-->", opening + ""); int len = output.length(); ImageSpan[] images = output.getSpans(len-1, len, ImageSpan.class); Log.e("images-->", images.length + ""); String imgURL = images[0].getSource(); Log.e("imgURL-->", imgURL + ""); //添加点击事件 output.setSpan(new ImageClickSpan(mContext, imgURL), len-1, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } else if(tag.equalsIgnoreCase("strike")) {//自定义解析<strike></strike>标签 int len = output.length(); Log.e("opening-->", opening + ""); if(opening) {//开始解析该标签,打一个标记 output.setSpan(new StrikethroughSpan(), len, len, Spannable.SPAN_MARK_MARK); } else {//解析结束,读出所有标记,取最后一个标记为当前解析的标签的标记(因为解析方式是便读便解析) StrikethroughSpan[] spans = output.getSpans(0, len, StrikethroughSpan.class); if (spans.length > 0) { for(int i = spans.length - 1; i >= 0; i--){ if(output.getSpanFlags(spans[i]) == Spannable.SPAN_MARK_MARK) { int start = output.getSpanStart(spans[i]); output.removeSpan(spans[i]); if (start != len) { output.setSpan(new StrikethroughSpan(), start, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } break; } } } } }else{//其他标签不再处理 Log.e("TAG-->", tag + "--不做处理"); } } } class ImageClickSpan extends ClickableSpan{ private Context context; private String url; public ImageClickSpan(Context context, String url){ this.context = context; this.url = url; } @Override public void onClick(View widget) { Log.e("TAG-->", "ImageClickSpan"); showPicDialog(url); } }
demo源码下载:
Github地址
CSDN下载地址