解决Android富文本无法显示rgb字体颜色和字体大小
Posted Steven Jon
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了解决Android富文本无法显示rgb字体颜色和字体大小相关的知识,希望对你有一定的参考价值。
问题
服务器返回数据:
<p>特价!特价!特价!特价优惠:<span style="color: rgb(225, 60, 57);font-size:22px;">【10元】</span>一件</p>
安卓移动端代码:
val htmlStr = "<p>特价!特价!特价!特价优惠:<span style=\\"color: rgb(225, 60, 57);font-size:22px;\\">【10元】</span>一件</p>"
findViewById<TextView>(R.id.tv_content).text = HtmlCompat.fromHtml(htmlStr, HtmlCompat.FROM_HTML_MODE_COMPACT)
安卓移动端显示:
至此,可以看出问题所在,【10元】
字体颜色和大小都有问题。
如何解决?
自定义标签,并使用Html.TagHandler
进行解析和属性修改
提供了Kotlin和Java两个版本,可以直接复制使用
HtmlTagHandler.kt
class HtmlTagHandler(private val tag: String?, private val context: Context) : Html.TagHandler
private var startIndex : Int? = 0
private val attributes = HashMap<String, String>()
override fun handleTag(opening: Boolean, tag: String?, output: Editable?, xmlReader: XMLReader?)
if (tag == this@HtmlTagHandler.tag)
parseAttributes(xmlReader)
if (opening)
startHandleTag(output)
else
endHandleTag(output)
attributes.clear()
private fun parseAttributes(xmlReader: XMLReader?)
try
val elementField: Field? = xmlReader?.javaClass?.getDeclaredField("theNewElement")
elementField?.isAccessible = true
val element: Any? = elementField?.get(xmlReader)
val attsField: Field? = element?.javaClass?.getDeclaredField("theAtts")
attsField?.isAccessible = true
val atts: Any? = attsField?.get(element)
val dataField: Field? = atts?.javaClass?.getDeclaredField("data")
dataField?.isAccessible = true
val data = dataField?.get(atts) as Array<*>
val lengthField: Field = atts.javaClass.getDeclaredField("length")
lengthField.isAccessible = true
val len = lengthField.get(atts) as Int
for (i in 0 until len)
attributes[data[i * 5 + 1] as String] = data[i * 5 + 4] as String
catch (e: Exception)
private fun startHandleTag(output: Editable?)
startIndex = output?.length
private fun endHandleTag(output: Editable?)
val stopIndex = output?.length
val style : String? = attributes["style"]
if (!TextUtils.isEmpty(style))
analysisStyle(startIndex, stopIndex, output, style)
/**
* 解析style属性
*
* @param startIndex startIndex
* @param stopIndex stopIndex
* @param editable editable
* @param style style
*/
private fun analysisStyle(startIndex: Int?, stopIndex: Int?, editable: Editable?, style: String?)
val attrArray = style?.split(";")
val attrMap = HashMap<String, String>()
if (attrArray != null)
for (attr in attrArray)
val keyValueArray = attr.split(":")
if (keyValueArray.size == 2)
// 去除前后空格
attrMap[keyValueArray[0].trim()] = keyValueArray[1].trim()
// 字体颜色
var color = attrMap["color"]
if (!TextUtils.isEmpty(color))
if (color!!.startsWith("rgb"))
color = color.replace("rgb(", "")
color = color.replace(")", "")
val rgbs = color.split(", ")
if (rgbs.size > 2)
color = toHex(rgbs[0].toInt(), rgbs[1].toInt(), rgbs[2].toInt())
try
editable?.setSpan(
ForegroundColorSpan(Color.parseColor(color)),
startIndex!!, stopIndex!!, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
)
catch (e: java.lang.Exception)
e.printStackTrace()
// 字体大小
var fontSize = attrMap["font-size"]
if (!TextUtils.isEmpty(fontSize))
fontSize = fontSize!!.split("px")[0]
try
val absoluteSize = sp2px(context, fontSize.toInt())
editable?.setSpan(
AbsoluteSizeSpan(absoluteSize), startIndex!!,
stopIndex!!, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
catch (e: java.lang.Exception)
e.printStackTrace()
companion object
private fun toHex(r : Int, g : Int, b : Int) : String
return "#" + toBrowserHexValue(r) + toBrowserHexValue(g) + toBrowserHexValue(b)
private fun toBrowserHexValue(number: Int) : String
val builder = StringBuilder(number.and(0xff).toString(16))
while (builder.length < 2)
builder.append("0")
return builder.toString().uppercase(Locale.getDefault())
private fun sp2px(context: Context, pxValue: Int) : Int
val fontScale = context.resources.displayMetrics.scaledDensity
return (pxValue * fontScale + 0.5f).toInt()
HtmlTagHandler.java
public class HtmlTagHandler implements Html.TagHandler
private final String tag;
private final Context context;
private final HashMap<String, String> attributes = new HashMap<>();
private int startIndex = 0;
public HtmlTagHandler(String tag, Context context)
this.tag = tag;
this.context = context;
@Override
public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader)
if (this.tag.equalsIgnoreCase(tag))
processAttributes(xmlReader);
if (opening)
startHandleTag(output);
else
endHandleTag(output);
attributes.clear();
private void processAttributes(XMLReader xmlReader)
try
Field elementField = xmlReader.getClass().getDeclaredField("theNewElement");
elementField.setAccessible(true);
Object element = elementField.get(xmlReader);
assert element != null;
Field attsField = element.getClass().getDeclaredField("theAtts");
attsField.setAccessible(true);
Object atts = attsField.get(element);
assert atts != null;
Field dataField = atts.getClass().getDeclaredField("data");
dataField.setAccessible(true);
String[] data = (String[]) dataField.get(atts);
Field lengthField = atts.getClass().getDeclaredField("length");
lengthField.setAccessible(true);
Object attsLength = lengthField.get(atts);
int len = attsLength == null ? 0 : (Integer) attsLength;
for (int i = 0; i < len; i++)
assert data != null;
attributes.put(data[i * 5 + 1], data[i * 5 + 4]);
catch (Exception ignored)
private void startHandleTag(Editable output)
startIndex = output.length();
private void endHandleTag(Editable output)
int stopIndex = output.length();
String style = attributes.get("style");
if (!TextUtils.isEmpty(style))
assert style != null;
analysisStyle(startIndex, stopIndex, output, style);
/**
* 解析style属性
*
* @param startIndex startIndex
* @param stopIndex stopIndex
* @param editable editable
* @param style style
*/
private void analysisStyle(int startIndex, int stopIndex, Editable editable, String style)
String[] attrArray = style.split(";");
Map<String, String> attrMap = new HashMap<>();
for (String attr : attrArray)
String[] keyValueArray = attr.split(":");
if (keyValueArray.length == 2)
// 去除前后空格
attrMap.put(keyValueArray[0].trim(), keyValueArray[1].trim());
String color = attrMap.get("color");
if (!TextUtils.isEmpty(color))
assert color != null;
if (color.startsWith("rgb"))
color = color.replace("rgb(", "");
color = color.replace(")", "");
String[] rgbs = color.split(", ");
color = toHex(Integer.parseInt(rgbs[0]), Integer.parseInt(rgbs[1]), Integer.parseInt(rgbs[2]));
try
editable.setSpan(new ForegroundColorSpan(Color.parseColor(color)), startIndex, stopIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
catch (Exception e)
e.printStackTrace();
String fontSize = attrMap.get("font-size");
if (!TextUtils.isEmpty(fontSize))
assert fontSize != null;
fontSize = fontSize.split("px")[0];
try
int size = sp2px(context, Integer.parseInt(fontSize));
editable.setSpan(new AbsoluteSizeSpan(size), startIndex, stopIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
catch (Exception e)
e.printStackTrace();
private static String toHex(int r, int g, int b)
return "#" + toBrowserHexValue(r) + toBrowserHexValue(g)
+ toBrowserHexValue(b);
private static String toBrowserHexValue(int number)
StringBuilder builder = new StringBuilder(
Integer.toHexString(number & 0xff));
while (builder.length() < 2)
builder.append("0");
return builder.toString().toUpperCase();
private static int sp2px(Context context, float spValue) 以上是关于解决Android富文本无法显示rgb字体颜色和字体大小的主要内容,如果未能解决你的问题,请参考以下文章
[Android开发]富文本TextView修改部分字体颜色大小加粗斜体下划线删除线,以及添加点击事件,插入本地或网络图片