Android 显示后台返回富文本rgb色值适配问题

最近做一个项目经常用到富文本去显示页面,但是富文本修改颜色样式显示不出效果,结果发现后端返回的颜色样式是rgb的格式,Android解析不出这格式,先看下两段一样颜色格式不同展现的效果

 //直接使用TextView显示富文本
  TextView.setText(Html.fromHtml("富文本内容"));
<p>
<span style="font-size: 14px;">检测到少量色斑,应预防紫外线照射问题,</span>
<span style="font-size: 14px; color: #ff0000;">做好肌</span>
<span style="font-size: 14px;">肤补水保湿工作,合理的休息,可以让新陈代谢有效地消除脸部色斑。</span>
</p>

在这里插入图片描述

<p>
<span style="font-size: 14px;">检测到少量色斑,应预防紫外线照射问题,</span>
<span style="font-size: 14px; color: rgb(230, 0, 0);">做好肌</span>
<span style="font-size: 14px;">肤补水保湿工作,合理的休息,可以让新陈代谢有效地消除脸部色斑。</span>
</p>

在这里插入图片描述

在不需要后端修改格式的前提下提供一个解决方式, 在别的博客中找到的方法,想链接一下博客地址,但找不到了

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.BackgroundColorSpan;
import android.text.style.ForegroundColorSpan;
import android.text.style.TextAppearanceSpan;
import android.util.Log;

import com.djm.smallappliances.utils.DisplayUtils;

import org.xml.sax.XMLReader;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

/**
 * created by MMF
 * on 2020/9/18
 * 解決富文本返回颜色格式rgb(230, 0, 0)解析不了问题
 */
public class CustomTagHandler implements Html.TagHandler {

    final HashMap<String, String> attributes = new HashMap<String, String>();
    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("myspan")) {
            if (opening) {
                startSpan(tag, output, xmlReader);
            } else {
                endSpan(tag, output, xmlReader);
                attributes.clear();
            }
        }
    }

    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) {
        }
    }

    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 bacgroundColor = attributes.get("background-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(bacgroundColor)) {
            if (bacgroundColor.startsWith("@")) {
                Resources res = Resources.getSystem();
                String name = bacgroundColor.substring(1);
                int colorRes = res.getIdentifier(name, "color", "android");
                if (colorRes != 0) {
                    output.setSpan(new BackgroundColorSpan(colorRes), startIndex, stopIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                }
            } else {
                if (bacgroundColor.startsWith("rgb")) {
                    bacgroundColor = bacgroundColor.replace("rgb(", "");
                    bacgroundColor = bacgroundColor.replace(")", "");
                    String[] rgbs = bacgroundColor.split(", ");
                    bacgroundColor = toHex(Integer.parseInt(rgbs[0]), Integer.parseInt(rgbs[1]), Integer.parseInt(rgbs[2]));
                }
                try {
                    output.setSpan(new BackgroundColorSpan(Color.parseColor(bacgroundColor)), startIndex, stopIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                } catch (Exception e) {
                    e.printStackTrace();
                    reductionFontColor(startIndex, stopIndex, output);
                }
            }
        }
        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 = DisplayUtils.dip2sp(mContext, Integer.parseInt(size));
            }
            output.setSpan(new AbsoluteSizeSpan(fontSizePx), 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<String, String> 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());
                }
            }
        }
        String color = attrMap.get("color");
        String bacgroundColor = attrMap.get("background-color");
        String fontSize = attrMap.get("font-size");
        if (!TextUtils.isEmpty(fontSize)) {
            fontSize = fontSize.split("px")[0];
        }
        if (!TextUtils.isEmpty(bacgroundColor)) {
            if (bacgroundColor.startsWith("@")) {
                Resources res = Resources.getSystem();
                String name = bacgroundColor.substring(1);
                int colorRes = res.getIdentifier(name, "color", "android");
                if (colorRes != 0) {
                    editable.setSpan(new BackgroundColorSpan(colorRes), startIndex, stopIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                }
            } else {
                if (bacgroundColor.startsWith("rgb")) {
                    bacgroundColor = bacgroundColor.replace("rgb(", "");
                    bacgroundColor = bacgroundColor.replace(")", "");
                    String[] rgbs = bacgroundColor.split(", ");
                    bacgroundColor = toHex(Integer.parseInt(rgbs[0]), Integer.parseInt(rgbs[1]), Integer.parseInt(rgbs[2]));
                }
                try {
                    editable.setSpan(new BackgroundColorSpan(Color.parseColor(bacgroundColor)), startIndex, stopIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                } catch (Exception e) {
                    e.printStackTrace();
                    reductionFontColor(startIndex, stopIndex, editable);
                }
            }
        }
        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 {
                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();
                    reductionFontColor(startIndex, stopIndex, editable);
                }
            }
        }
        if (!TextUtils.isEmpty(fontSize)) {
            int fontSizePx = 14;
            if (null != mContext) {
                fontSizePx = DisplayUtils.dip2sp(mContext, Integer.parseInt(fontSize));
            }
            editable.setSpan(new AbsoluteSizeSpan(fontSizePx), startIndex, stopIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
    }

    /**
     * 还原为原来的颜色
     *
     * @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);
        }
    }

    public 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();
    }
}

使用方式:

String htmlStr = "富文本内容".replace("span", "myspan");
TextView.setText(Html.fromHtml(htmlStr, null, new CustomTagHandler(mContext, holder.tvCause.getTextColors())));

Android8.0还是9.0会过滤span标签导致handleTag方法监听不到span标签,所以修改为"myspan"(具体Android版本查清再来更新),“myspan”这个标签可以按自己想的去定义,定义后在CustomTagHandler中的handleTag监听中的判断要改成自己定义的标签

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值