Keywords: Android TextView
github:https://github.com/grantland/android-autofittextview
本篇主讲autofittextview库,这个开源项目主要用于输入文字显示,自动根据文字长度调整文字大小以保证单行/指定行数能全显示,文字缩放到最小的时候用省略号代替。
效果图对比:
上图展示效果而言,我大胆猜想其实现原理:
-
缩放文字textSize ,缩放有最大、最小比例限制
-
addOnTextSizeChangeListener() 文字发生变化,内容长度变化重新测量,决定是否需要缩放文字textSize 或者是否达到缩放临界值
带着个人猜想来注意了解这个开源项目,先来看项目结构
AutofitHelper的create()函数做了两件事
-
通过创建自身实例,获取不同手机各自的字体缩放比例计算字体缩放到最小的像素值,以及一些其他的基本变量赋值
-
获取自定义属性赋值变量
public static AutofitHelper create(TextView view, AttributeSet attrs, int defStyle) {
AutofitHelper helper = new AutofitHelper(view);
boolean sizeToFit = true;
if (attrs != null) {
Context context = view.getContext();
int minTextSize = (int) helper.getMinTextSize();
float precision = helper.getPrecision();
TypedArray ta = context.obtainStyledAttributes(
attrs,
R.styleable.AutofitTextView,
defStyle,
0);
sizeToFit = ta.getBoolean(R.styleable.AutofitTextView_sizeToFit, sizeToFit);
minTextSize = ta.getDimensionPixelSize(R.styleable.AutofitTextView_minTextSize,
minTextSize);
precision = ta.getFloat(R.styleable.AutofitTextView_precision, precision);
ta.recycle();
helper.setMinTextSize(TypedValue.COMPLEX_UNIT_PX, minTextSize)
.setPrecision(precision);
}
helper.setEnabled(sizeToFit);
return helper;
}
setEnabled()方法用于控制是否支持自动缩放适应,该方法与autoTextView自定义属性sizeToFit对应。为什么一个boolean变量就可以控制呢?看过源码就一目了然了
public AutofitHelper setEnabled(boolean enabled) {
if (mEnabled != enabled) {
mEnabled = enabled;
if (enabled) {
mTextView.addTextChangedListener(mTextWatcher);
mTextView.addOnLayoutChangeListener(mOnLayoutChangeListener);
autofit();
} else {
mTextView.removeTextChangedListener(mTextWatcher);
mTextView.removeOnLayoutChangeListener(mOnLayoutChangeListener);
mTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize);
}
}
return this;
}
不管是文字长度发生变化还是控件宽高随着文字大小发生变变化而变化,都会回调到autofit()函数,随着TextSize大小变化重新设定,通过OnTextSizeChangeListener回调给我们newTextSize 、oldTextSize,AutofitHelper还对外公开了几个代码设置方法,有兴趣可以试试。
AutofitTextView一个自定义TextView,代码并没有什么大的改动,一些方法重载,通过AutoHelper类代理实现,这里就不过多叙述,这里再多提一点,非常重要的一点:
弱引用不能随便用!!
博主在这里为什么提这点呢?且看AutofitLayout项目中的源码
public class AutofitLayout extends FrameLayout {
private WeakHashMap<View, AutofitHelper> mHelpers = new WeakHashMap<View, AutofitHelper>();
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
super.addView(child, index, params);
TextView textView = (TextView) child;
AutofitHelper helper = AutofitHelper.create(textView)
.setEnabled(mEnabled);
if (mPrecision > 0) {
helper.setPrecision(mPrecision);
}
if (mMinTextSize > 0) {
helper.setMinTextSize(TypedValue.COMPLEX_UNIT_PX, mMinTextSize);
}
mHelpers.put(textView, helper);
}
}
public AutofitHelper getAutofitHelper(TextView textView) {
return mHelpers.get(textView);
}
一目了然,完全没问题嘛,如果是以前我也一定会这样认为!不过前不久遇到一个同事开发的代码,暴露了一个诡异bug,登录请求回调Callback放入了弱引用,app有不同机型手机出现登录的进度框一直转动没法取消,代码一直都没问题,其他手机都ok,问题出在哪呢?问题还很难复现!几经周折才找到罪魁祸首:弱引用,当Callback实例被回收,函数回调不到Activity主线程,dialog一直无法消失。
下面我们来科普一下弱引用
弱引用(WeakReference):如果一个对象只具有弱引用,那就类似于可有可物的生活用品。弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它 所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程, 因此不一定会很快发现那些只具有弱引用的对象。 弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。
相比较于弱引用这种做法,个人更推荐使用类似ViewPager (纯属个人观点,若有错误欢迎指出)
private List<OnPageChangeListener> mOnPageChangeListeners;
public void addOnPageChangeListener(OnPageChangeListener listener) {
if (mOnPageChangeListeners == null) {
mOnPageChangeListeners = new ArrayList<>();
}
mOnPageChangeListeners.add(listener);
}
以上内容为上午学习所得,分享出来,希望各位朋友喜欢。如果你觉得博主这篇博客还行,还请不吝"❤"一个,谢谢!
交流群初创,欢迎各位加入
网友评论