全局修改默认字体,通过反射也能做到

简介:

一、前言

本文依然属于 Android 修改字体的系列,本系列开始会介绍一些比较方便的全局修改的方案,越往后的方案可能会越好一些,但是不一定最适用你现在的项目。

今天介绍的就是其中的一个,使用反射的方式,修改 Typeface 中的某个字体,来达到全局替换的目的。

二、替换默认字体的思路

本文的很多预备的知识点,应该在之前的文章中就已经说清楚了,有兴趣可以去看看完整的文章,《》。

这里为了保证逻辑完整,还是大概说一下思路。

2.1 修改Typeface 的某个默认字体

首先需要明确一点,在 Android 中,所有操作字体的动作,都会使用到 Typeface 这个类。而系统默认的一些字体,也会在 Typeface 被加载的时候进行初始化,因为这些步骤在它的静态代码块内完成。

/f-init.png

而这些字体都会定义成了 static final 的,所以一般我们是不能去修改它们的。

/f-staticfinal.png

但是我们是可以使用反射的方式去修改被标记为 static final 的常量的,这个后面再将细节。

也就是说,我们只需要在初始化的实际,替换掉某个默认的字体,然后在Theme 内将默认字体字体标记为该字体,就可以达到替换的目的。

2.2 在 TextView 中默认的字体

在 TextView 的构造方法里,设置字体的方法是 setTypefaceFromAttrs() ,下面是该方法的方法签名。

/f-setAttr.png

在该方法的参数中,如果 familyName 为 null 的时候,会根据传入的 typefaceIndex 去设置对应的字体,传入到 setTypeface() 方法中。

再来看看 TextView 的构造方法中,获取这几个参数的地方。在默认什么都不设置的情况下, familyName 就是为 null,而 typefaceIndex 为 -1。这两个参数会先从 TextAppearance 中读取属性,再从 TextView 本身设置的 xml 属性中读取,后者会覆盖前者。

可是 typefaceIndex 还会有一些其它的操作,例如 inputType 为 password 的时候,就会强行修改为 MONOSPACE。

/f-getAttr.png

最终,将处理后的结构,传递给 setTypefaceFromAttrs() 方法。

通过这些细节,我们就可以了解到,是在有一些情况下,是可以保证 TextView 使用的是我们的某个被加载到 Typeface 中的默认字体的。

条件就是:

fontFamily == null && typefaceIndex != -1

2.3 在 Theme 中,修改字体为默认字体样式

对于一些默认的字体样式,是可以直接在 Theme 中进行设置的,它的优先级低于在页面布局的 xml 中,为 TextView 设置的字体样式,但是如果不设置,那么在 Theme 中的设置将会生效。

这个没什么好说的,我这里用的主题就是 AppTheme,所以我在它里面修改 android:typeface 就可以了。

/f-theme.png

三、通过反射修改字体

到这里,基本的概念就已经讲解清楚了,那么我们就开始实际编写代码来替换字体了。

3.1 修改 Theme

在 App 的主题中,修改 android:typeface 为 serif。

/f-theme.png

注意,这里随便选了一个默认字体,实际上使用 monospace 也是可以的,只需要和后面我们替换的字体保持一致即可。

当然这里不推荐使用 monospace ,因为 TextView 本身还有一些逻辑会将 typefaceIndex 设置成 monospace,所以我们不要替换它比较好。

3.2 通过反射修改 Typeface 的字体

在 Typeface 中,是有一些被标记为 static final 的默认字体,因为上一步的 Theme 中,就是设置的 serif ,所以我们这里替换它就好了。

完整的方法非常的简单,就是通过反射拿到 Typeface.SERIF,然后使用反射将它修改成我们需要的字体即可。

/f-replace.png

因为这里修改了 static final 的值,所以需要额外调用 setAccessible() 方法,它会修改 AccessibleObject 中的 overide 为 true,这个标记的意思,就是关闭对这个字段改写的安全检查,从而让我们可以替换 static final 的字段。

3.3 在入口的地方,调用替换的方法

接下来就清晰了,我们只需要在 App 启动的时候,调用一下 changeDefaultFont() 方法。

这里直接在 Application.onCreate() 方法中,调用即可。

/f-myapp.png

3.4 验证运行结果

这个没什么了,直接写个 Demo,正常使用 TextView 就可以了。


本文转自承香墨影博客园博客,原文链接:http://www.cnblogs.com/plokmju/p/7608048.html,如需转载请自行联系原作者


相关文章
|
4月前
|
缓存 编解码 监控
reservedCodecCacheSize属性详解与配置建议
reservedCodecCacheSize属性详解与配置建议
|
6月前
|
计算机视觉
vs2017修改从父级或项目默认设置继承项
vs2017修改从父级或项目默认设置继承项
163 0
在vuecli3怎么设置全局公用的样式变量?
在vuecli3怎么设置全局公用的样式变量?
168 0
|
Java 开发工具 Windows
五、实现自定义配置属性动态加载
在我们日常开发项目时,经常需要自定义一些配置属性用于我们项目的一些启动配置,这里我们就直接在application-dev配置文件中直接实现一下自定义配置属性的读取与使用,便于我们在dev和prod配置文件来回切换。
98 0
五、实现自定义配置属性动态加载
X11/XWindow更改属性代码
X11/XWindow更改属性代码
115 0
|
Java 应用服务中间件
publiccms中,怎么修改默认的端口8080以及默认上下文名称
publiccms中,怎么修改默认的端口8080以及默认上下文名称
132 0
|
C++
VS 显示方法引用的设置方法
VS 中Codelens的设置面板没有相关的设置项?那如何调整出方法的引用呢?
2243 0
VS 显示方法引用的设置方法
|
安全 Windows
ToolStripStatusLabel 没有 InvokeRequired 属性的解决办法
ToolStripStatusLabel 没有 InvokeRequired 属性的解决办法 当编写多线程程序时,你希望在线程中修改 Form 窗体上的控件的文本等属性, 但你会得到一个错误:线程间操作无效: 从不是创建控件“xxx”的线程访问它。
1666 0