一、遇到的问题:

当用户调整系统字体大小的时候,APP的字体一般也都会跟随改变,进而导致某些界面布局排版混乱。

下面先说一下关于sp单位的理解

sp单位除了受屏幕密度影响外,还受到用户的字体大小影响,通常情况下,建议使用sp来跟随用户字体大小设置。除非一些特殊的情况,不想跟随系统字体变化的,可以使用dp”。按照这么说,布局宽高固定写死的地方应该统一用dp显示字体,因为一旦用户在设置中调大字体,宽高为固定值的布局显示就乱了。

二、 解决方案:

1.  强制实现所有界面都的字体都不随系统字体大小而改变,在工程的BaseActivity中添加下面的代码。利用Android的Configuration类中的fontScale属性,其默认值为1,会随系统调节字体大小而发生变化,如果我们强制让其等于默认值,就可以实现字体不随调节改变,

@Override

public Resources getResources() {

Resources resources = super.getResources();

if (resources != null) {

Configuration configuration = resources.getConfiguration();

if (configuration != null && configuration.fontScale != 1.0f) {

configuration.fontScale = 1.0f;//这里只设置字体,故不使用下面注释的方法

// configuration.setToDefaults();

resources.updateConfiguration(configuration, resources.getDisplayMetrics());

}

}

return resources;

}

注意: Android 8.0后在Application中复写上述方法是无效的 (原因暂不清楚,有知道的大佬欢迎指出)。此外,在任意一个Activity中如上覆盖了getResources方法后,会让其它Activity的字体也变的独立于系统配置(这里的Activity只针对重新create的,如当前 Activity 的 fragment,因为没有重新onCreate,就不会重绘进而改变字体)。我的理解是,新的 Activity 会载入上面更新后的 Configuration,而现有的 Activity 则不会更新。所以此方式我只建议用在BaseActivity中实现全部界面字体不随系统更改。

2.  在具体的界面把不想要放大的View字体单位设置为dp

三、原理解析:

到底为什么设置为sp,会导致字体随系统字体大小而改变?

从文字设定大小的入口看,TextView.setTextSize(float size)方法来看:

/**

* 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.

*

*

Note: if this TextView has the auto-size feature enabled than this function is no-op.

*

* @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.

*

*

Note: if this TextView has the auto-size feature enabled than this function is no-op.

*

* @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) {

if (!isAutoSizeEnabled()) {

setTextSizeInternal(unit, size, true /* shouldRequestLayout */);

}

}

private void setTextSizeInternal(int unit, float size, boolean shouldRequestLayout) {

Context c = getContext();

Resources r;

if (c == null) {

r = Resources.getSystem();

} else {

r = c.getResources();

}

setRawTextSize(TypedValue.applyDimension(unit, size, r.getDisplayMetrics()),

shouldRequestLayout);

}

@UnsupportedAppUsage

private void setRawTextSize(float size, boolean shouldRequestLayout) {

if (size != mTextPaint.getTextSize()) {

mTextPaint.setTextSize(size);

if (shouldRequestLayout && mLayout != null) {

// Do not auto-size right after setting the text size.

mNeedsAutoSizeText = false;

nullLayouts();

requestLayout();

invalidate();

}

}

}

可以看到,如果没有设置字体单位的时候,默认会分配 TypedValue.COMPLEX_UNIT_SP ,即 sp 单位,而最终的值会通过TypedValue.applyDimension(unit, size, r.getDisplayMetrics()) 方法计算出来赋值给 setRawTextSize 方法,所以接下来看怎么计算的:

/**

* Converts an unpacked complex data value holding a dimension to its final floating

* point value. The two parameters unit and value

* are as in {@link #TYPE_DIMENSION}.

*

* @param unit The unit to convert from.

* @param value The value to apply the unit to.

* @param metrics Current display metrics to use in the conversion --

* supplies display density and scaling information.

*

* @return The complex floating point value multiplied by the appropriate

* metrics depending on its unit.

*/

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;

}

可以看到,当单位为 COMPLEX_UNIT_SP时,取值为 value * metrics.scaleDensity;所以接下来看 metrics.scaleDensity 的取值:

/**

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

public void setTo(DisplayMetrics o) {

if (this == o) {

return;

}

widthPixels = o.widthPixels;

heightPixels = o.heightPixels;

density = o.density;

densityDpi = o.densityDpi;

scaledDensity = o.scaledDensity;

xdpi = o.xdpi;

ydpi = o.ydpi;

noncompatWidthPixels = o.noncompatWidthPixels;

noncompatHeightPixels = o.noncompatHeightPixels;

noncompatDensity = o.noncompatDensity;

noncompatDensityDpi = o.noncompatDensityDpi;

noncompatScaledDensity = o.noncompatScaledDensity;

noncompatXdpi = o.noncompatXdpi;

noncompatYdpi = o.noncompatYdpi;

}

public void setToDefaults() {

widthPixels = 0;

heightPixels = 0;

density = DENSITY_DEVICE / (float) DENSITY_DEFAULT;

densityDpi = DENSITY_DEVICE;

scaledDensity = density;

xdpi = DENSITY_DEVICE;

ydpi = DENSITY_DEVICE;

noncompatWidthPixels = widthPixels;

noncompatHeightPixels = heightPixels;

noncompatDensity = density;

noncompatDensityDpi = densityDpi;

noncompatScaledDensity = scaledDensity;

noncompatXdpi = xdpi;

noncompatYdpi = ydpi;

}

注释说明了,scaleDensity 不仅仅受设备的 density 影响,还受用户设定的字体尺寸影响。DisplayMetrics.scaleDensity 在 DisplayMetrics 类中,并没有初始化的地方,可它是一个 public 的字段,也就是说可以被外部赋值初始化。真正为 DisplayMetrics 中各个字段赋值的地方,在 ResourcesImpl 中,有一个 updateConfiguration() 方法,在其中,就有对 scaleDensity 进行初始化的逻辑。

public void updateConfiguration(Configuration config, DisplayMetrics metrics,

CompatibilityInfo compat) {

//省略部分代码

//...........

if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) {

mMetrics.densityDpi = mConfiguration.densityDpi;

mMetrics.density =

mConfiguration.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;

}

// Protect against an unset fontScale.

mMetrics.scaledDensity = mMetrics.density *

(mConfiguration.fontScale != 0 ? mConfiguration.fontScale : 1.0f);

//省略部分代码

//...........

}

可以看到,这里又引入了一个新的计算因子,fontScale。而从 Configuration 的源码又了解到,fontScale 默认值为 1 ,这也就是为什么通常情况下,density 和 scaleDensity 的值是相等的,它们分别影响了 dp 和 sp 最终渲染出来的像素尺寸。

所以,我们要控制字体不随系统字体改变的本质,就是通过修改 fontScale 的值为1,这也就是我们方法1这么做的原因。

好文分享:当你在设置里修改字体大小的时候,到底在修改什么

Android View篇之 字体大小 调整滑杆的实现

Android 仿微信/支付宝 字体大小 调整控件

来源:oschina

链接:https://my.oschina.net/u/4398725/blog/4547034

android改变整个app字体大小,Android APP字体随系统字体调整造成界面布局混乱问题解决方案...相关推荐

  1. Android APP字体随系统字体调整造成界面布局混乱问题解决方案

    一.遇到的问题 当用户调整系统字体大小的时候,APP的字体一般也都会跟随改变,进而导致某些界面布局排版混乱. 下面先说一下关于sp单位的理解 sp单位除了受屏幕密度影响外,还受到用户的字体大小影响,通 ...

  2. android 7.1 字体更换,Android APP字体随系统字体调整造成界面布局混乱问题解决方案...

    一.遇到的问题: 当用户调整系统字体大小的时候,APP的字体一般也都会跟随改变,进而导致某些界面布局排版混乱. 下面先说一下关于sp单位的理解 sp单位除了受屏幕密度影响外,还受到用户的字体大小影响, ...

  3. Android App修改字体大小,且不随系统字体大小更改

    在做混合开发时发现,无论是APP内的字体大小,还是前端的字体大小,都会随着系统字体大小发生变化.当遇到老人字体(特大号字体)时,有些页面的布局就乱掉了.而玩过游戏的都知道,所有游戏APP的字体都不会随 ...

  4. Android全局修改字体大小,Android 仿微信全局字体大小调整

    image 目录 一.前言 二.效果预览 三.实现步骤 1.自定义字体调整控件 2.滑动按钮改变当前页面预览字体大小 3.返回时,保存放大倍数并重启应用 4.初始化应用时配置字体放大倍数. 四.Dem ...

  5. R语言ggplot2可视化改变字体大小实战:单个图片设置字体大小、全局设置字体大小

    R语言ggplot2可视化改变字体大小实战:单个图片设置字体大小.全局设置字体大小 目录

  6. 修改ToolBar的标题、子标题字体大小和颜色,toolbar menu字体的大小和颜色以及注意事项

    在 Android 5.0 开始推出一个 Material Design 风格的导航Toolbar 控件.由于Toolbar的可定制度高,所以已经逐步替代掉了ActionBar.可以自定义以下几种元素 ...

  7. html代码字号div style=,div字体大小设置 css设置div中字体大小尺寸样式

    div字体大小设置 css设置div中字体大小尺寸样式设置篇 在css div布局中常常对div字体大小设置,这篇ThinkCSS为大家介绍div中字体大小尺寸样式设置,通过直接在div标签加字体大小 ...

  8. div怎么在css中设置字体大小,div字体大小设置 css设置div中字体大小尺寸样式

    div字体大小设置 css设置div中字体大小尺寸样式设置篇 在css div布局中常常对div字体大小设置,这篇ThinkCSS为大家介绍div中字体大小尺寸样式设置,通过直接在div标签加字体大小 ...

  9. android改变整个app字体大小,Android系统字体大小如何影响app的字体大小?

    在Android应用开发过程中,一定会碰到本来完美的布局,在系统字体大小设置[最大]时变成一团浆糊.解决办法网上也有很多,但是分析原理的却几乎没看到.博主在碰到问题的第一时间也是直接用了网上的方法,即 ...

最新文章

  1. PAT甲级1108 Finding Average :[C++题解]stof、字符串变成浮点数、try和catch捕获异常、C++语法题
  2. python_day10_并发编程
  3. SAP 3D visual enterprise viewer 9.0 的下载方式
  4. java json 易用_Java中 Json的使用
  5. leetcode 115. 不同的子序列(dp)
  6. 有了 IP 地址,为什么还要用 MAC 地址?
  7. 【BZOJ3566】概率充电器,树形概率DP
  8. “评论王争夺赛”活动,第4期开始啦!
  9. Qt实现判断鼠标左右键信号
  10. HTML跳转php没反应的问题解决
  11. 【LeetCode】马三来刷题之Valid Anagram
  12. 基于wincap写抓包程序
  13. python 爬虫 爬取 小米有品 全网 商品数据
  14. Mikrotik RouterOS路由器和华为交换机链路聚合+VRRP+单线多拨
  15. 朋友圈利诱裂变遭封杀,私域流量成裂变新关键
  16. IIS 服务器的安装和配置
  17. android手机更改手机密码,手机忘记密码如可解决 安卓手机重置密码教程【详解】...
  18. 【稻韵果香,以梦为家】云和恩墨大讲堂电子期刊第九期
  19. tomat startup.bat 日志乱码问题解决
  20. 超详细IntelliJ IDEA安装教程

热门文章

  1. python iterable对象_Python迭代器Iterable判断方法解析
  2. R语言,中文排序问题
  3. 数据结构c语言版期末考试试题及答案,数据结构c语言版试题大全(含答案)
  4. 中学德育工作汇报材料
  5. 微软投屏器 android,微软 Your Phone 新功能:可同时投屏多款 Android 应用
  6. 成都市武侯计算机实验小学官网,成都市武侯计算机实验小学:挖掘英语教材 聚焦核心素养...
  7. 大学计算机课代表竞选稿,竞选大学课代表演讲稿
  8. JAVA JDK1.8 时间戳与时间格式化 实用工具类
  9. 测试矩阵是什么,小孩子都懂的,你该不会不知道吧
  10. 热点 | 天猫精灵卖出100万台,中国智能音箱市场将井喷?