开篇
不BB, 直奔主题。
场景
固定宽度的TextView,在不同尺寸的手机上显示效果不一样:小屏上会显示成两行,大屏上显示一行。
在遇到这种情况时,我们该如何应对呢?我们的第一想法当然是自定义一个自动适配字体大小的TextView。
效果截屏
我们看到,在TextView宽度不变的情况下,它会根据文本长度自动调整字体大小。当然,在字符串不变的情况下,它同样会根据TextView宽度自动调整字体大小。
简析源码
public class AutoTextSizeView extends AppCompatTextView implements IViewAttrDelegate{ public AutoTextSizeView(Context context) { super(context);
initAttr(context, null, 0);
} public AutoTextSizeView(Context context, AttributeSet attrs) { super(context, attrs);
initAttr(context, attrs, 0);
} public AutoTextSizeView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr);
initAttr(context, attrs, defStyleAttr);
} @Override
public void initAttr(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
setGravity(Gravity.CENTER);
setMaxLines(1);
}1、我们在监听到View宽度发生变化时,自动调整字体大小:
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); //do nothing if it's width was not changed
if (oldw == w){ return;
}
resetTextSizeIfNecessary();
}2、因为自动适配字体大小的过程是一个不断循环去匹配的一个过程,所以我们开启一个线程去干这件事。
private void resetTextSizeIfNecessary() {
removeCallbacks(r);
postDelayed(r, 20);
} private Runnable r = new Runnable() { @Override
public void run() {
loop();
}
};3、匹配字体大小的核心算法:当前字体大小
float textSize = getPaint().getTextSize();
A、字符宽度 >
TextView的宽度,说明textSize大了,调整字体大小:textSize = (textSize + textSize / 2) / 2;
B、字符宽度 <TextView的宽度 - 一个字符宽度,说明textSize小了,调整字体大小:textSize = (textSize + textSize * 2) / 2;
通过递归反复匹配字体大小,直到匹配到相对合适的字体大小为止。这个过程往往经过1次或者几次就能匹配到,利用二分法的思想匹配效率很高。
private void loop() {
CharSequence text = getText(); if (text == null || text.length() == 0) return; int maxTextWidth = getWidth() - getPaddingLeft() - getPaddingRight(); float textWidth = getPaint().measureText(text, 0, text.length()); float textSize = getPaint().getTextSize(); float alphaWidth = getPaint().measureText("a"); if (textWidth >= (maxTextWidth - alphaWidth * 2) && textWidth <= maxTextWidth) { //匹配到合适的字体大小了
//这里我试图直接调用invalidate()刷新视图,但是并没有达到想要的结果
//我们必须重新setText(...)
//reset text
//call it's onMeasure(int, int) and onDraw(Canvas)
//增加这个方法,只是为了区分是自动适配字体大小后setText(...)还是我们手动调用setText(...)
setAutoSizeText(text, false); return;
} //字体大了
//here is the idea of binary search
if (textWidth > maxTextWidth) {
textSize = textSize + textSize / 2;
getPaint().setTextSize(textSize / 2);
} //字体小了
if (textWidth < maxTextWidth - alphaWidth * 2) {
textSize = textSize + textSize * 2;
getPaint().setTextSize(textSize / 2);
}
loop();
} public void setAutoSizeText(CharSequence text, boolean resizeImmediately){
setText(text); if (resizeImmediately)
resetTextSizeIfNecessary();
}从26.0匹配到87.75,之经历过了4次匹配,匹配效率是真的很高。
童鞋们,如果你们觉得不错的话给我点个吧,谢谢!!!
作者:JustinRoom
链接:https://www.jianshu.com/p/ec3cf23044b6
共同学习,写下你的评论
评论加载中...
作者其他优质文章


