AutoSize属性问题探索
如有错误,欢迎指出
Google在Android 8.0(API level 26)中,为TextView加入了一个动态属性AutoSize。
在布局文件中,直接设置autoSizeTextType属性为uniform即可。这样,文本内容便会忽略android:textSize属性,从水平和垂直两个方向上缩放文本的内容。
android:autoSizeTextType="uniform"
android:autoSizeMaxTextSize="35dp"
android:autoSizeStepGranularity="1dp"
android:autoSizeMinTextSize="1dp"
在API26以下,实现AutoSize需要支持库
<!-- 引入命名空间 -->
xmlns:app="http://schemas.android.com/apk/res-auto"
app:autoSizeTextType="uniform"
app:autoSizeMaxTextSize="35dp"
app:autoSizeStepGranularity="1dp"
app:autoSizeMinTextSize="1dp"
最近在使用autoSize时遇到了几个坑:
-
不能与SingleLine一起用
与single连用后,当文本过长时会显示省略号,改用maxLines=1即可 -
RadioButton的autosize属性
经过多次试验,支持库在某些安卓版本上好像无法实现RadioButton的autosize属性
API | app | android |
---|---|---|
25 | NO | NO |
26 | NO | YES |
28 | YES | YES |
我们知道,在API26中为TextView引入了AutoSize属性,而RadioButton -> CompoundButton(接口) -> Button -> TextView,因此在API26+中通过android设置的autosize属性可以生效
现在来分析通过app设置的autosize属性
support v7中的RadioButton的完整类名为:android.support.v7.widget.AppCompatRadioButton
public class AppCompatRadioButton extends RadioButton implements TintableCompoundButton {
private final AppCompatCompoundButtonHelper mCompoundButtonHelper;
private final AppCompatTextHelper mTextHelper;
......
public AppCompatRadioButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(TintContextWrapper.wrap(context), attrs, defStyleAttr);
this.mCompoundButtonHelper = new AppCompatCompoundButtonHelper(this);
this.mCompoundButtonHelper.loadFromAttributes(attrs, defStyleAttr);
this.mTextHelper = new AppCompatTextHelper(this);
this.mTextHelper.loadFromAttributes(attrs, defStyleAttr);
}
......
}
可以看到,AppCompatRadioButton中存在一个与text相关的成员变量mTextHelper
AppCompatTextHelper(TextView view) {
this.mView = view;
this.mAutoSizeTextHelper = new AppCompatTextViewAutoSizeHelper(this.mView);
}
终于看到autosize了,现在去看看mAutoSizeTextHelper
class AppCompatTextViewAutoSizeHelper {
AppCompatTextViewAutoSizeHelper(TextView textView) {
this.mTextView = textView;
this.mContext = this.mTextView.getContext();
}
void setAutoSizeTextTypeWithDefaults(int autoSizeTextType) {......}
void setAutoSizeTextTypeUniformWithConfiguration(int autoSizeMinTextSize, int autoSizeMaxTextSize, int autoSizeStepGranularity, int unit) throws IllegalArgumentException {......}
void setAutoSizeTextTypeUniformWithPresetSizes(@NonNull int[] presetSizes, int unit) throws IllegalArgumentException {......}
......
}
可以发现 AppCompatTextViewAutoSizeHelper 类正是实现autosize属性的重要类,那么,是如何调用的呢?
我们再回到AppCompatRadioButton
类
public AppCompatRadioButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(TintContextWrapper.wrap(context), attrs, defStyleAttr);
this.mCompoundButtonHelper = new AppCompatCompoundButtonHelper(this);
this.mCompoundButtonHelper.loadFromAttributes(attrs, defStyleAttr);
this.mTextHelper = new AppCompatTextHelper(this);
this.mTextHelper.loadFromAttributes(attrs, defStyleAttr);
}
通过搜索,mTextHelper
仅出现在构造函数中
我们来看 this.mTextHelper = new AppCompatTextHelper(this);
AppCompatTextHelper(TextView view) {
this.mView = view;
this.mAutoSizeTextHelper = new AppCompatTextViewAutoSizeHelper(this.mView);
}
AppCompatTextViewAutoSizeHelper(TextView textView) {
this.mTextView = textView;
this.mContext = this.mTextView.getContext();
}
可知,this.mTextHelper = new AppCompatTextHelper(this);
旨在初始化,还未涉及autosize属性的初始化
现在来看this.mTextHelper.loadFromAttributes(attrs, defStyleAttr);
从名称看,该方法用于加载属性
//AppCompatTextHelper.java
@SuppressLint({"NewApi"})
void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
......
this.mAutoSizeTextHelper.loadFromAttributes(attrs, defStyleAttr);
if (AutoSizeableTextView.PLATFORM_SUPPORTS_AUTOSIZE && this.mAutoSizeTextHelper.getAutoSizeTextType() != 0) {
int[] autoSizeTextSizesInPx = this.mAutoSizeTextHelper.getAutoSizeTextAvailableSizes();
if (autoSizeTextSizesInPx.length > 0) {
if ((float)this.mView.getAutoSizeStepGranularity() != -1.0F) {
this.mView.setAutoSizeTextTypeUniformWithConfiguration(this.mAutoSizeTextHelper.getAutoSizeMinTextSize(), this.mAutoSizeTextHelper.getAutoSizeMaxTextSize(), this.mAutoSizeTextHelper.getAutoSizeStepGranularity(), 0);
} else {
this.mView.setAutoSizeTextTypeUniformWithPresetSizes(autoSizeTextSizesInPx, 0);
}
}
}
......
}
可以看到,该方法中存在setAutoSizeTextXXX
然而它要求AutoSizeableTextView.PLATFORM_SUPPORTS_AUTOSIZE
为true,也就是VERSION.SDK_INT >= 27;
这里可以解释在API28上app设置autosize属性生效
继续看this.mAutoSizeTextHelper.loadFromAttributes(attrs, defStyleAttr);
//AppCompatTextViewAutoSizeHelper.java
void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
......
if (this.supportsAutoSizeText()) {
if (this.mAutoSizeTextType == 1) {
......
this.setupAutoSizeText();
}
} else {
this.mAutoSizeTextType = 0;
}
}
//这里的mTextView是AppCompatRadioButton 应该返回true
private boolean supportsAutoSizeText() {
return !(this.mTextView instanceof AppCompatEditText);
}
//这个方法设置了一些属性
private boolean setupAutoSizeText() {
if (this.supportsAutoSizeText() && this.mAutoSizeTextType == 1) {
if (!this.mHasPresetAutoSizeValues || this.mAutoSizeTextSizesInPx.length == 0) {
int autoSizeValuesLength = 1;
for(float currentSize = (float)Math.round(this.mAutoSizeMinTextSizeInPx); Math.round(currentSize + this.mAutoSizeStepGranularityInPx) <= Math.round(this.mAutoSizeMaxTextSizeInPx); currentSize += this.mAutoSizeStepGranularityInPx) {
++autoSizeValuesLength;
}
int[] autoSizeTextSizesInPx = new int[autoSizeValuesLength];
float sizeToAdd = this.mAutoSizeMinTextSizeInPx;
for(int i = 0; i < autoSizeValuesLength; ++i) {
autoSizeTextSizesInPx[i] = Math.round(sizeToAdd);
sizeToAdd += this.mAutoSizeStepGranularityInPx;
}
this.mAutoSizeTextSizesInPx = this.cleanupAutoSizePresetSizes(autoSizeTextSizesInPx);
}
this.mNeedsAutoSizeText = true;
} else {
this.mNeedsAutoSizeText = false;
}
return this.mNeedsAutoSizeText;
}
到这里后续已经没有调用了,也就是说,在API27以下AppCompatRadioButton并没有实现autosize属性
那么AppCompatTextView和AppCompatButton是如何实现的呢?
这里主要分析AppCompatTextView
public class AppCompatTextView extends TextView implements TintableBackgroundView,
TintableCompoundDrawablesView, AutoSizeableTextView {
......
public AppCompatTextView(
@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(TintContextWrapper.wrap(context), attrs, defStyleAttr);
ThemeUtils.checkAppCompatTheme(this, getContext());
mBackgroundTintHelper = new AppCompatBackgroundHelper(this);
mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
mTextHelper = new AppCompatTextHelper(this);
mTextHelper.loadFromAttributes(attrs, defStyleAttr);
mTextHelper.applyCompoundDrawablesTints(); //比RadioButton多出
mTextClassifierHelper = new AppCompatTextClassifierHelper(this);
}
......
public void setAutoSizeTextTypeWithDefaults(
@TextViewCompat.AutoSizeTextType int autoSizeTextType) {
if (Build.VERSION.SDK_INT >= 26) {
super.setAutoSizeTextTypeWithDefaults(autoSizeTextType);
} else {
if (mTextHelper != null) {
mTextHelper.setAutoSizeTextTypeWithDefaults(autoSizeTextType);
}
}
}
public void setAutoSizeTextTypeUniformWithConfiguration(
int autoSizeMinTextSize,
int autoSizeMaxTextSize,
int autoSizeStepGranularity,
int unit) throws IllegalArgumentException {
if (Build.VERSION.SDK_INT >= 26) {
super.setAutoSizeTextTypeUniformWithConfiguration(
autoSizeMinTextSize, autoSizeMaxTextSize, autoSizeStepGranularity, unit);
} else {
if (mTextHelper != null) {
mTextHelper.setAutoSizeTextTypeUniformWithConfiguration(
autoSizeMinTextSize, autoSizeMaxTextSize, autoSizeStepGranularity, unit);
}
}
}
......
相比于AppCompatRadioButton,它实现了AutoSizeableTextView接口,重写了setAutoSizeTextXXX
方法,因此可以实现autosize属性