您的位置:首页 > 移动开发

Android系统字体大小如何影响app的字体大小?

2016-12-25 00:54 666 查看
在Android应用开发过程中,一定会碰到本来完美的布局,在系统字体大小设置【最大】时变成一团浆糊。解决办法网上也有很多,但是分析原理的却几乎没看到。博主在碰到问题的第一时间也是直接用了网上的方法,即在BaseActivity中重写getResources方法如下

@Override
public Resources getResources() {
Resources res = super.getResources();
Configuration config=new Configuration();
config.setToDefaults();
res.updateConfiguration(config,res.getDisplayMetrics());
return res;
}


这个方法是有效的。

但是作为开发人员必须懂得举一反三,而要举一反三就必须要“知其所以然”,于是博主就去探寻了一番,才有了此篇文章。

1.字体大小如何设置

这个简单,就拿TextView来说,设置字体大小调用setTextSize方法就行了。如果你直接以px为单位设置字体大小,那么应用字体大小是绝对不会被系统字体所影响的,但是绝大多数时候,我们用的单位都是sp,sp是什么?sp = scaled pixel 即缩放了的像素值。而如果用了sp就一定会受系统字体大小的影响。

我们拿TextView来举例,看看它的setTextSize方法

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()));
}


看一眼代码,至少可以确定一件事情:设置的字体大小在内部做了计算和变换。

没错,就是这个applyDimension方法干的好事!!

我们跟进去看看先:

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;
}


事实一目了然,我们设置进去的value值,这个方法返回的是value*metrics.scaledDensity 问题肯定出在scaledDensity这个属性身上!!!

好了,字体大小的设置到此结束。

2. scaledDensity真面目

根据网上提供的办法,我们知道字体大小的影响跟Resources有关(具体原因待分析)。于是博主在Resources.java源码中进行了查找,发现了一个重要的方法

public void updateConfiguration(Configuration config,
DisplayMetrics metrics) {
updateConfiguration(config, metrics, null);
}


然后是具体实现的方法:

public void updateConfiguration(Configuration config,
DisplayMetrics metrics, CompatibilityInfo compat) {
synchronized (mAccessLock) {
... 省略代码 ...

mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale;

... 省略代码 ...
}
synchronized (sSync) {
if (mPluralRule != null) {
mPluralRule = NativePluralRules.forLocale(config.locale);
}
}
}


相信大家都看到了,mMetrics.scaledDensity的值其实是受mConfiguration.fontScale影响的。那么我们的研究对象又一次转变了,变成了fontScale

此时,我们对照一下,网上的解决系统字体大小影响的代码片段

@Override
public Resources getResources() {
Resources res = super.getResources();
Configuration config=new Configuration();
config.setToDefaults();
res.updateConfiguration(config,res.getDisplayMetrics());
return res;
}


看来路子是走对了,这里也是对Configuration进行了设置,并且还调用了updateConfiguration方法。

并且我还告诉你,这里的config.setToDefaults()方法内部第一句代码就是fontScale=1。

那么分析到这里,我们基本可以推测:如果修改系统的字体大小,fontScale肯定会改变!

3. 最终解决

首先,推测是需要验证的。我们可以编写一个demo,在MainActivity的onCreate方法中打印fontScale值

Log.d("Javine","fontScale = "+getResources().getConfiguration().fontScale);


博主的是锤子T1,打印出来的结果是

标准 —– fontScale = 1.0

较大 —– fontScale = 1.1

最大 —– fontScale = 1.4

到此为止,我们还是不能百分之百确定问题一定是因为fontScale值的变化引起的。

我们还需要做最后一件事情——通过修改fontScale值来修复字体大小的问题!

跟网上的解决办法一样,重载Activity的getResources方法如下:

@Override
public Resources getResources() {
//获取到resources对象
Resources res = super.getResources();
//修改configuration的fontScale属性
res.getConfiguration().fontScale = 1;
//将修改后的值更新到metrics.scaledDensity属性上
res.updateConfiguration(null,null);
return res;
}


经博主测试,问题完美解决!!并且,对比网上的解决办法,我们并没有新建一个Configuration对象,从性能角度上说,这个办法更优。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息