这个标题想了好久还是没想到如何简洁明了地把需求说清楚。。就随便取了一个。
先看需求,在开发过程中,有时候需要对后端返回对字符串做部分的高亮展示。如图所示,假定以下都是后端接口返回的,需要对部分特定对内容做高亮处理,包括了字体、颜色等做特殊处理。
如果是的话,你可以继续往下看了。
这个需求的难点在于,特殊处理的字符个数未知、位置未知(没办法将字符串分成多个接口字段),也没有固定的上下文,可能随机分布在字符串的各个地方,并且需要对一个textview的部分文字进行不同颜色大小的展示。因此不好进行处理。
基于这个我提出一个解决方案供大家参考。
首先需要明确地是,这个方案需要后端地配合,和后端约定一种格式用于标记字符串中需要特殊处理的部分。
比如我们是约定了被<span></span>包含的字符串代表需要高亮展示。然后我们只需要针对被<span></span>包含的内容取出做特殊处理即可。比如上面的字符串,后端需要返回的格式就是“xxx本应用会按照<span>《固原通隐私协议》</span>的规定xxx”。至于为什么选择这种方式,是考虑到为了方便前端h5能快速识别。
将需求拆解以下,我们需要做的事情就是两部分,第一部分获取标签的内容,然后对这部分分开设置字体样式。
第一部分,假定有一个<span>标签,那么文案可以分成3部分,有两个<span>标签就可以划分成5部分(姑且认为标签不会出现在头部和尾部,这类情况还需要另外处理,但这里就不讲解了,处理思路同理)。如图所示,可以看到n个<span>标签,整个文案可以分成2n+1部分。我们可以用java的split方法对字符串进行分割。
srcString.split("<span>|</span>")
这样就可以获取到包含各个部分的内容。
第二部分就是对特殊部分进行文字处理。这里Android 提供了对一个textview部分文字做高亮处理的SpanString和SpanStringBuilder,不需要使用多个textview,那样代码写的太不优雅了。这里就不做讲解了,有时间会另起一篇博客进行讲解,这里认为大家都了解他们的使用了。
有了这个思路实现就方便许多了。
下面是我封装的一个工具类,用于识别<span></span>标签,并且能将标签内容设置不同的颜色大小。
这里为了方便扩展,我使用了可变参数作为属性,可以传入文字大小、颜色两个属性,可以只传一个,也可以两个都传。
public static SpannableStringBuilder parseString(Context context, String srcString,
int... attrs) {
//获取字符串各个部分
String[] arr = srcString.split("<span>|</span>");
//添加文案1部分
SpannableStringBuilder stringBuilder = new SpannableStringBuilder(arr[0]);
for (int i = 0; i < arr.length / 2; i++) {
// 对高亮部分进行处理
SpannableString spannableString = new SpannableString(arr[2 * i + 1]);
switch (attrs.length) {
case 2:
ForegroundColorSpan colorSpan =
new ForegroundColorSpan(context.getResources().getColor(attrs[1]));
spannableString.setSpan(colorSpan, 0, spannableString.length(),
Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
case 1:
AbsoluteSizeSpan sizeSpan = new AbsoluteSizeSpan(attrs[0], true);
spannableString.setSpan(sizeSpan, 0, spannableString.length(),
Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
default:
break;
}
stringBuilder.append(" ").append(spannableString).append(" ");
stringBuilder.append(arr[2 * i + 2]);
}
return stringBuilder;
}
如果后续有需要,还可以添加对应的点击事件,只需要将attrs固定参数个数,传入可变的listner,然后一一对应传给对应的spanstring即可。
使用也很方便
textview.setText(parseString(str));