只能修改html以实现更改字体的排版工具,工具类分享--便捷地改变字体样式

需求

在Android UI开发上,我们通常需要对文字进行排版来获得更好的视觉效果。常常要求我们改变一段字体中某些字体的样式。如下一个简单的界面,每一item明显地数字的字体需要加粗而且字体大小也不一样了:

0818b9ca8b590ca3270a3433284dd417.png

对于UI的Item的实现,有如下三种方式:

用两个TextView(直接不考虑。。。)

使用Html的方式

Spannable对象

HTML方式

其实,Android其提供了android.text.Html类来支持部分的Html格式标签。这其中包括常用的字体大小颜色设置,文本链接等。使用起来也比较方便,只需要使用Html类转换一下即可,举例,下面的代码来改变字体样式:

0818b9ca8b590ca3270a3433284dd417.png

效果:

0818b9ca8b590ca3270a3433284dd417.png

Spannable对象

现在我们已经知道使用Android中的Html类可以实现字体样式的改变,但是这样写实在是丑陋极了。目前看来在JAVA代码中植入Html标记看起来很简单是因为有现有的工具来实现。但是想想我们的字符串可能会是从资源文件中获取,我们的颜色值需要在运行的时候才确定。我们最终不得不使用丑陋的字符串拼接或者格式化字符串资源来生成适当的Html字符串,然后使用Html类来解析。

这里我们有个更好的解决方案,使用Spannable对象。

0818b9ca8b590ca3270a3433284dd417.png

可以看出,Spannable继承自Spanned接口,而实际上,Spanned继承自CharSequence接口,在TextView的setText(CharSequence text)方法中,要求的参数正好是一个CharSequence对象,因此,我们可以通过Spannable对象来直接使用setText来完成文本的设置。在使用中通常使用Spannable spn = new SpannableString(“字符串”);或者通过SpannableStringBuilder对象来进行构建。

给Spannable对象设置样式

在构建Spannable对象以后,就可以使用Spannable#setSpan(Obj what, int start, int end, int flags)方法来进行样式的设置了,其中参数what是具体样式的实现对象,start则是该样式开始的位置,end对应的是样式结束的位置,参数flags,定义在Spannable中的常量,常用的有:

flags

意义

Spanned.SPAN_EXCLUSIVE_EXCLUSIVE

不包含两端start和end所在的端点(a,b)

Spanned.SPAN_EXCLUSIVE_INCLUSIVE

不包含端start,但包含end所在的端点(a,b]

Spanned.SPAN_INCLUSIVE_EXCLUSIVE

包含两端start,但不包含end所在的端点[a,b)

Spanned.SPAN_INCLUSIVE_INCLUSIVE

包含两端start和end所在的端点 [a,b]

而在start和end相同的情况下,则只对start所在字符的当前行起作用。

样式分析

用来构建样式的具体的类都在android.text.style包下,都继承自CharacterStyle类,常用的有ForegroundColorSpan(改变字体颜色),AbsoluteSizeSpan(改变字体大小),StyleSpan(可以设字体为粗体,倾斜,下划线等)。

0818b9ca8b590ca3270a3433284dd417.png

CharacterStyle有N多种的实现,基本满足你对字体样式的需求,[ 了解更多]

改变字体颜色的例子:

0818b9ca8b590ca3270a3433284dd417.png

效果

0818b9ca8b590ca3270a3433284dd417.png

相比使用HTML类,这才是我们熟悉的面向对象的写法,而且它明显地要比使用HTML类要简洁和简单并且容易维护。

有了上面的使用范例,完成文章开头提到的那个样式还难吗?在得到“N负责”这样的字符串后,只需要对字符串使用StyleSpan指定为加粗样式并指定改变的位置为【Start:0,End:1】就可以了啊,等等,什么?指定位置?这样的Hard Code真的好吗?不要忘了这个N可能是两位数、甚至三位数。

0818b9ca8b590ca3270a3433284dd417.png

进一步实现

最后一件值得考虑的事情是如何决定哪部分的字符串是否需要使用Span。很明显在这里我们需要使用正则表达式(但也不是万能的)。

有了这个思路之后,考虑把它封装成工具类,至于为什么不使用继承来实现?这是因为在Android Sdk中已经提供了大量的实现类(20个以上),使用继承不如使用组合来得更灵活,也比较通用。

对外提供接口,返回特定样式的字符串,传入需要处理的字符串,处理所用的正则表达式,和组合的样式,这样的粒度也是刚好适合的,每个View所需要的样式不一样,需要处理的字符串也不有差异。

/** * *@author csl 2015年5月11日 下午3:33:03 * */

public final class SpanUtils {

private SpanUtils() {

}

/** * 构造特定格式的字符串 * *@param source *@param pattern *@param styles *@return */

public static CharSequence createSpannable(CharSequence source,Pattern pattern, CharacterStyle... styles) {

SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(source);

Matcher matcher = pattern.matcher(source);

while (matcher.find()) {

int start = matcher.start();

int end = matcher.end();

applyStylesToSpannable(spannableStringBuilder, start, end, styles);

}

return spannableStringBuilder;

}

private static SpannableStringBuilder applyStylesToSpannable(SpannableStringBuilder source, int start, int end,CharacterStyle... styles) {

for (CharacterStyle style : styles) {

source.setSpan(CharacterStyle.wrap(style), start, end,Spanned.SPAN_INCLUSIVE_INCLUSIVE);

}

return source;

}

}

如下则是简单使用,使字符串中的数字加粗和大小设为20sp:

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值