失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > android html 字体颜色代码 Android TextView通过解析html显示不同颜色和大小

android html 字体颜色代码 Android TextView通过解析html显示不同颜色和大小

时间:2023-09-07 01:05:31

相关推荐

android html 字体颜色代码 Android TextView通过解析html显示不同颜色和大小

先贴一张效果图

效果

介绍

通过SpannableString、SpannableStringBuilder可以很方便的给TextView加上各种各样的样式,比如不同的颜色和大小,这里就不多说了,具体可以参考下面这篇文章:

SpannableString与SpannableStringBuilder使用

TextView通过使用Html.fromHtml方法可以加载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 for each

// 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("strong")) {

start(mSpannableStringBuilder, new Bold());

} else if (tag.equalsIgnoreCase("b")) {

start(mSpannableStringBuilder, new Bold());

} else if (tag.equalsIgnoreCase("em")) {

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);

}

}

查看源码应该只支持这几种,不过看最后一句代码发现它是支持自定义标签处理的,就是说你可以自己重写TagHandler去实现。

思路

结合前面说的SpannableString和参考Html类源码可以实现我们这篇文章的需求,如果你只是想解析html在TextView上显示不同的颜色,那系统已经实现了,但前提是要用font标签,比如这样:

测试TextView显示不同颜色和大小

在Html类源码中发现:

private static void startFont(SpannableStringBuilder text,

Attributes attributes) {

String color = attributes.getValue("", "color");

String face = attributes.getValue("", "face");

int len = text.length();

text.setSpan(new Font(color, face), len, len, Spannable.SPAN_MARK_MARK);

}

private static void endFont(SpannableStringBuilder text) {

int len = text.length();

Object obj = getLast(text, Font.class);

int where = text.getSpanStart(obj);

text.removeSpan(obj);

if (where != len) {

Font f = (Font) obj;

if (!TextUtils.isEmpty(f.mColor)) {

if (f.mColor.startsWith("@")) {

Resources res = Resources.getSystem();

String name = f.mColor.substring(1);

int colorRes = res.getIdentifier(name, "color", "android");

if (colorRes != 0) {

ColorStateList colors = res.getColorStateList(colorRes, null);

text.setSpan(new TextAppearanceSpan(null, 0, 0, colors, null),

where, len,

Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

}

} else {

int c = Color.getHtmlColor(f.mColor);

if (c != -1) {

text.setSpan(new ForegroundColorSpan(c | 0xFF000000),

where, len,

Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

}

}

}

if (f.mFace != null) {

text.setSpan(new TypefaceSpan(f.mFace), where, len,

Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

}

}

}

系统处理了font标签的color和face属性,但是没有处理size属性,这个让人很郁闷,没办法,我们只有通过自定义TagHandler来处理了,这里我参考了这篇文章:

Android 多样化显示TextView以及扩展Html自定义标签

至此,TextView解析html显示不同颜色和大小的功能通过自定义TagHandler已经可以实现了,但是这种方式也有一定的局限性,就是后台给你返回的html片段的样式要使用标签中的属性,就像我上面举例的font中的color属性,但是可能后台返回的数据不一定是这样,我们后台返回的就是这样的:

选项C

如果是这样的情况,那就需要再对style属性进行解析,获取里面的样式属性,所以这里只是给大家提供一个思路,具体怎么处理还是要看后台返回的数据。

结尾

最后附上我处理style属性的自定义TagHandler,有不对的地方,欢迎大家指正!

package wdcloud.testdemo;

import android.content.Context;

import android.content.res.ColorStateList;

import android.content.res.Resources;

import android.graphics.Color;

import android.text.Editable;

import android.text.Html;

import android.text.Spannable;

import android.text.Spanned;

import android.text.TextUtils;

import android.text.style.AbsoluteSizeSpan;

import android.text.style.ForegroundColorSpan;

import android.text.style.TextAppearanceSpan;

import android.util.Log;

import org.xml.sax.XMLReader;

import java.lang.reflect.Field;

import java.util.HashMap;

import java.util.Map;

public class CustomTagHandler implements Html.TagHandler {

private final String TAG = "CustomTagHandler";

private int startIndex = 0;

private int stopIndex = 0;

private ColorStateList mOriginColors;

private Context mContext;

public CustomTagHandler(Context context,ColorStateList originColors){

mContext = context;

mOriginColors = originColors;

}

@Override

public void handleTag(boolean opening, String tag, Editable output,

XMLReader xmlReader) {

processAttributes(xmlReader);

if(tag.equalsIgnoreCase("span")){

if(opening){

startSpan(tag, output, xmlReader);

}else{

endSpan(tag, output, xmlReader);

attributes.clear();

}

}

}

public void startSpan(String tag, Editable output, XMLReader xmlReader) {

startIndex = output.length();

}

public void endSpan(String tag, Editable output, XMLReader xmlReader){

stopIndex = output.length();

String color = attributes.get("color");

String size = attributes.get("size");

String style = attributes.get("style");

if (!TextUtils.isEmpty(style)){

analysisStyle(startIndex,stopIndex,output,style);

}

if (!TextUtils.isEmpty(size)) {

size = size.split("px")[0];

}

if(!TextUtils.isEmpty(color)){

if (color.startsWith("@")) {

Resources res = Resources.getSystem();

String name = color.substring(1);

int colorRes = res.getIdentifier(name, "color", "android");

if (colorRes != 0) {

output.setSpan(new ForegroundColorSpan(colorRes), startIndex, stopIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

}

} else {

try {

output.setSpan(new ForegroundColorSpan(Color.parseColor(color)), startIndex, stopIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

} catch (Exception e) {

e.printStackTrace();

reductionFontColor(startIndex,stopIndex,output);

}

}

}

if (!TextUtils.isEmpty(size)) {

int fontSizePx = 16;

if (null != mContext){

fontSizePx = DisplayUtil.sp2px(mContext,Integer.parseInt(size));

}

output.setSpan(new AbsoluteSizeSpan(fontSizePx), startIndex, stopIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

}

}

final HashMap attributes = new HashMap();

private void processAttributes(final XMLReader xmlReader) {

try {

Field elementField = xmlReader.getClass().getDeclaredField("theNewElement");

elementField.setAccessible(true);

Object element = elementField.get(xmlReader);

Field attsField = element.getClass().getDeclaredField("theAtts");

attsField.setAccessible(true);

Object atts = attsField.get(element);

Field dataField = atts.getClass().getDeclaredField("data");

dataField.setAccessible(true);

String[] data = (String[])dataField.get(atts);

Field lengthField = atts.getClass().getDeclaredField("length");

lengthField.setAccessible(true);

int len = (Integer)lengthField.get(atts);

/**

* MSH: Look for supported attributes and add to hash map.

* This is as tight as things can get :)

* The data index is "just" where the keys and values are stored.

*/

for(int i = 0; i < len; i++)

attributes.put(data[i * 5 + 1], data[i * 5 + 4]);

}

catch (Exception e) {

}

}

/**

* 还原为原来的颜色

* @param startIndex

* @param stopIndex

* @param editable

*/

private void reductionFontColor(int startIndex,int stopIndex,Editable editable){

if (null != mOriginColors){

editable.setSpan(new TextAppearanceSpan(null, 0, 0, mOriginColors, null),

startIndex, stopIndex,

Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

}else {

editable.setSpan(new ForegroundColorSpan(0xff2b2b2b), startIndex, stopIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

}

}

/**

* 解析style属性

* @param startIndex

* @param stopIndex

* @param editable

* @param style

*/

private void analysisStyle(int startIndex,int stopIndex,Editable editable,String style){

Log.e(TAG,"style:"+style);

String[] attrArray = style.split(";");

Map attrMap = new HashMap<>();

if (null != attrArray){

for (String attr:attrArray){

String[] keyValueArray = attr.split(":");

if (null != keyValueArray && keyValueArray.length == 2){

// 记住要去除前后空格

attrMap.put(keyValueArray[0].trim(),keyValueArray[1].trim());

}

}

}

Log.e(TAG,"attrMap:"+attrMap.toString());

String color = attrMap.get("color");

String fontSize = attrMap.get("font-size");

if (!TextUtils.isEmpty(fontSize)) {

fontSize = fontSize.split("px")[0];

}

if(!TextUtils.isEmpty(color)){

if (color.startsWith("@")) {

Resources res = Resources.getSystem();

String name = color.substring(1);

int colorRes = res.getIdentifier(name, "color", "android");

if (colorRes != 0) {

editable.setSpan(new ForegroundColorSpan(colorRes), startIndex, stopIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

}

} else {

try {

editable.setSpan(new ForegroundColorSpan(Color.parseColor(color)), startIndex, stopIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

} catch (Exception e) {

e.printStackTrace();

reductionFontColor(startIndex,stopIndex,editable);

}

}

}

if (!TextUtils.isEmpty(fontSize)) {

int fontSizePx = 16;

if (null != mContext){

fontSizePx = DisplayUtil.sp2px(mContext,Integer.parseInt(fontSize));

}

editable.setSpan(new AbsoluteSizeSpan(fontSizePx), startIndex, stopIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

}

}

}

使用方式:

TextView tv_ExtendTest = (TextView) findViewById(R.id.tv_extend_test);

tv_ExtendTest.setText(Html.fromHtml(htmlContent,null,new CustomTagHandler(TextViewExtendActivity.this,tv_ExtendTest.getTextColors())));

测试发现高版本Android系统中(如8.0),系统已经把span给解析了,所以不会再把span的解析回调给自定义TagHandler,这种情况下只需换一个系统没有解析的标签,最好是自定义的,比如之类的。

如果觉得《android html 字体颜色代码 Android TextView通过解析html显示不同颜色和大小》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。