背景
最近修复一个bug时遇到一个问题, TextView中显示的是SpannableString, 原有项目中自定义TextView是通过二分法找到一个合适的TextView能将字体完全展示的TextSize, 但是通过AbsoluteSizeSpan给SpannableString设置的字体大小是不受到TextView的textSize属性影响的,所以SpannableString的自适应需要有一套单独的方式.
实现
开始收到思路局限一直想使用和普通String相同的思路, 通过计算不同字体所需要的显示宽度,动态设置字体大小, 但是获取SpannableString的属性是个相对比较麻烦的工作, 而且这种方式使用场景受到局限,不能适用只有部分文字(或者所有文字都不设置AbsoluteSizeSpan)的情况.
通过查Android api发现设置SpannableString的字体除了AbsoluteSizeSpan外还有个RelativeSizeSpan, 从字面上理解,一个是绝对大小, 一个是相对大小, 有了这个设置相对大小的方法就简单多了, 可以通过可用宽度(TextView能显示的宽度)和所需宽度(显示当前大小所需要的宽度)计算出缩放比例, 关键代码如下:
private void refitSpannableString(CharSequence text, int width) {
if (width > 0) {
SpannableString targetString = new SpannableString(text);
int availableWidth = width - getPaddingLeft() - getPaddingRight();
float desiredWidth = Layout.getDesiredWidth(targetString, getPaint());
//text所需宽度>TextView可用宽度,并且TextView字体大小>设置的最小字体,才会重新设置字体大小
if (desiredWidth > availableWidth && getTextSize() > getMinTextSize()) {
float scale = availableWidth / desiredWidth;
//缩放后的字体不能小于设置的最小字体
if (getTextSize() * scale < getMinTextSize()) {
scale = getMinTextSize() / getTextSize();
setTextSize(mMinTextSize);
}
targetString.setSpan(new RelativeSizeSpan(scale),
0, targetString.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
setText(targetString);
}
}
}
自定义TextView代码:https://download.youkuaiyun.com/download/qq_30496695/10889594