设计师辛辛苦苦做出设计稿,开发人员辛辛苦苦把UI调好了,但是在Android用户修改系统的默认字体大小,原先的设计很容易失效,变得非常难看,考虑你的用户人群,又不想因为用户变更默认字体大小导致app的样式走样,我们可以这么做:

1.字体使用dp/dip代替sp

dp/dip(device independent pixels):一种基于屏幕密度的抽象单位。在每英寸160点的显示器上,1dp=1px。不同设备有不同的显示效果,这个和设备硬件有关。
sp(Scaled Pixels):主要用于字体显示,与刻度无关的一种像素,与dp类似,但是可以根据用户的字体大小首选项进行缩放。

查看TextView的源码可以发现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/**
* Set the default text size to the given value, interpreted as "scaled
* pixel" units. This size is adjusted based on the current density and
* user font size preference.
*
* @param size The scaled pixel size.
*
* @attr ref android.R.styleable#TextView_textSize
*/
@android.view.RemotableViewMethod
public void setTextSize(float size) {
setTextSize(TypedValue.COMPLEX_UNIT_SP, size);
}
/**
* Set the default text size to a given unit and value. See {@link
* TypedValue} for the possible dimension units.
*
* @param unit The desired dimension unit.
* @param size The desired size in the given units.
*
* @attr ref android.R.styleable#TextView_textSize
*/
public void setTextSize(int unit, float size) {
Context c = getContext();
Resources r;
if (c == null)
r = Resources.getSystem();
else
r = c.getResources();
setRawTextSize(TypedValue.applyDimension(
unit, size, r.getDisplayMetrics()));
}
private void setRawTextSize(float size) {
if (size != mTextPaint.getTextSize()) {
mTextPaint.setTextSize(size);
if (mLayout != null) {
nullLayouts();
requestLayout();
invalidate();
}
}
}

TypedValue.applyDimension()源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public static float applyDimension(int unit, float value,
DisplayMetrics metrics)
{
switch (unit) {
case COMPLEX_UNIT_PX:
return value;
case COMPLEX_UNIT_DIP:
return value * metrics.density;
case COMPLEX_UNIT_SP:
return value * metrics.scaledDensity;
case COMPLEX_UNIT_PT:
return value * metrics.xdpi * (1.0f/72);
case COMPLEX_UNIT_IN:
return value * metrics.xdpi;
case COMPLEX_UNIT_MM:
return value * metrics.xdpi * (1.0f/25.4f);
}
return 0;
}

dp与sp的换算差别只在于metrics.density和metrics.scaledDensity,

1
2
3
4
5
6
/**
* A scaling factor for fonts displayed on the display. This is the same
* as {@link #density}, except that it may be adjusted in smaller
* increments at runtime based on a user preference for the font size.
*/
public float scaledDensity;

因此,sp和dp的区别是乘以一个scale。

2.通过重写系统方法禁用

在Application重写以下方法即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Override
public void onConfigurationChanged(Configuration newConfig) {
if (newConfig.fontScale != 1)//非默认值
getResources();
super.onConfigurationChanged(newConfig);
}
@Override
public Resources getResources() {
Resources res = super.getResources();
if (res.getConfiguration().fontScale != 1) {//非默认值
Configuration newConfig = new Configuration();
newConfig.setToDefaults();//设置默认
res.updateConfiguration(newConfig, res.getDisplayMetrics());
}
return res;
}

通过重写方法,把fontScale重置为默认值。此方式无侵入,仅对当前App有效。

个人博客:http://hjhrq1991.info

如有转发,请注明来源!


参考:
[1]:http://blog.csdn.net/vipycm/article/details/44264199/
[2]:http://blog.csdn.net/sunshinetan/article/details/53954468/