(写在题前,Html.fromHtml()方法也可以实现处理html标签的功能,但一般适用于最简简单单的显示文本内容的功能需求,如果TextView本身有其他效果需要自定义且已经用到了Span进行处理或是效果与文本内容本身的实际有效长度有关(标签本身其实不是有效内容),可能用Html.fromHtml()就有很大限制了。
其实就是使用Span富文本处理html标签更加灵活。)
先说结论,直接上代码。
String title="xxxxxxx";//其中含有<sub></sub>等标签
tv.setText(getTabSpan(title,tv.getPaint());
/**
* 处理标签<sup></sup>等
* @param title
* @param textPaint
* @return
*/
public static SpannableStringBuilder getTabSpan(String title, TextPaint textPaint) {
SpannableStringBuilder spanBuilder=new SpannableStringBuilder(title);
spanBuilder=getHtmlSpan(spanBuilder,textPaint,"<sup>","</sup>");
spanBuilder=getHtmlSpan(spanBuilder,textPaint,"<sub>","</sub>");
spanBuilder=getHtmlSpan(spanBuilder,textPaint,"<strong>","</strong>");
//期待更多支持的标签。。。
return spanBuilder;
}
private static SpannableStringBuilder getHtmlSpan(SpannableStringBuilder spanBuilder, TextPaint textPaint,String pre,String suffix) {
int fontSizeSp=(int)(textPaint.getTextSize()/textPaint.density);
String key=pre+"(.+?)"+suffix;
CharacterStyle span;
Pattern p;
int preLength=pre.length();
int suffixLength=suffix.length();
String title=spanBuilder.toString();
try {
p = Pattern.compile(key);
Matcher m = p.matcher(title);
//LogSuperUtil.i("cnki_wiki_data","fontSizeSp="+fontSizeSp);
while (m.find()) {
int startIndex=m.start();
int endIndex=m.end();//是表达式结束的位置,并不是后缀开始的位置。
int spanStartIndex=startIndex+preLength;
int spanEndIndex=endIndex-suffixLength;
if("<sup>".equals(pre)) {
span = new SuperscriptSpan();// 需要重复!
spanBuilder.setSpan(span,spanStartIndex,spanEndIndex,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
AbsoluteSizeSpan sizeSpan=new AbsoluteSizeSpan(fontSizeSp,false);
spanBuilder.setSpan(sizeSpan,spanStartIndex,spanEndIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}else if("<sup>".equals(pre)) {
span = new SuperscriptSpan();// 需要重复!
spanBuilder.setSpan(span,spanStartIndex,spanEndIndex,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
AbsoluteSizeSpan sizeSpan=new AbsoluteSizeSpan(fontSizeSp,false);
spanBuilder.setSpan(sizeSpan,spanStartIndex,spanEndIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}else if("<strong>".equals(pre)) {
span = new StyleSpan(android.graphics.Typeface.BOLD);// 需要重复!
spanBuilder.setSpan(span,spanStartIndex,spanEndIndex,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
//LogSuperUtil.i("cnki_wiki_data","上标 start="+start+",end="+end);*/
spanBuilder.delete(endIndex-suffixLength,endIndex);
spanBuilder.delete(startIndex,startIndex+preLength);
title=spanBuilder.toString();
m=p.matcher(title);
}
} catch (Exception e) {
p = Pattern.compile("[^0-9]");
}
return spanBuilder;
}
最重要的是架构设计,是思想,当然最最重要的是技术关键点。
从踩过的坑中去总结,重要的几个知识点要知道。
1.SpannableStringBuilder的delete方法不会影响到本身已设置的富文本效果,索引不会自动移位。这保证了对<sup>15</sup>N度这种文本处理后,删除“<sup>”和“</sup>”字符串字样不会影响“15”字样的上标效果。
2.SpannableStringBuilder spanBuilder=new SpannableStringBuilder(charSq);
如果charSq已经是个富文本,那么spanBuilder不会破坏已有的富文本效果。
当然,在本例中,在1的基础上,2的用途可能就用不上了。因为拿到SpannableStringBuilder的实例引用,就可以多次处理想要的富文本效果。
另外,在实现关键字处理高亮显示标红的效果时,也对正则表达式的应用有一点总结。
代码是这样的:
private SpannableStringBuilder getKeywordSpan(SpannableStringBuilder spanBuilder) {
String pre="###";
String suffix="\$\$\$";
String key=pre+"(.+?)"+suffix;
CharacterStyle span;
Pattern p;
int preLength=pre.length();
int suffixLength=suffix.length();
suffixLength=3;//强制
String title=spanBuilder.toString();
try {
p = Pattern.compile(key);
Matcher m = p.matcher(title);
int color=mContext.getResources().getColor(R.color.red);
//LogSuperUtil.i("cnki_wiki_data","fontSizeSp="+fontSizeSp);
while (m.find()) {
int startIndex=m.start();
int endIndex=m.end();//是表达式结束的位置,并不是后缀开始的位置。
int spanStartIndex=startIndex+preLength;
int spanEndIndex=endIndex-suffixLength;
span = new ForegroundColorSpan(color);// 需要重复!
spanBuilder.setSpan(span,spanStartIndex,spanEndIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
//LogSuperUtil.i("cnki_wiki_data","上标 start="+start+",end="+end);*/
spanBuilder.delete(spanEndIndex,endIndex);
spanBuilder.delete(startIndex,spanStartIndex);
title=spanBuilder.toString();
m=p.matcher(title);
}
} catch (Exception e) {
p = Pattern.compile("[^0-9]");
}
return spanBuilder;
}
其实就是匹配“###xx$$$”这个,由于$这个符号在正则中表示表达式结束,那么需要转义,$才是表示的$本身。而在Java中,这个字符本身也是特殊字符,需要转义,\表示的才是真正的这个字符,所以,想在正则表达中真正表示$这个字符,在正则中就要写成\$,这就有了代码中的写法。
而匹配后,处理字符串“###xx$$$”,要删除的字符串长度是3("$$$"的长度),而不是"$$$"(其实调试的话会发现,Match匹配到的是“$$$”)。
以后再遇到需要显示Html中的标签时,这是个不错的选择,特别是自定义的TextView本身已用到Span去处理东西时,比如实现“... 展开”这种处理。
最后
以上就是淡然小鸽子最近收集整理的关于Android 使用Span富文本处理Html标签的全部内容,更多相关Android内容请搜索靠谱客的其他文章。
发表评论 取消回复