解决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富文本无法显示rgb字体颜色和字体大小

[Android开发]富文本TextView修改部分字体颜色大小加粗斜体下划线删除线,以及添加点击事件,插入本地或网络图片

富文本设置文字颜色和字体

富文本框显示文字长度 超出变色

iOS使用NSMutableAttributedString 实现富文本(不同颜色字体下划线等)

如何在grapesjs的默认富文本编辑器上添加颜色选择器来更改字体颜色?