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

9333988f7dd4c06b0751aad120f93b30.png

在 Android 下使用自定义字体已经是一个比较常见的需求了,最近也做了个比较深入的研究。

那么按照惯例我又要出个一篇有关 Android 修改字体相关的文章,但是写下来发现内容还挺多的,所以我决定将它们拆分一下,分几篇来详细的讲解(可能是五篇)。主要会是一些常用的替换字体的方案,***还会介绍一些全局替换的方案,当然也会包含***的 『Fonts in XML』的方案。

期待你持续关注。

本篇是本系列的第四篇,之前已经发布的文章,有兴趣可以先看看。

一、前言

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

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

二、替换默认字体的思路

本文的很多预备的知识点,应该在之前的文章中就已经说清楚了,有兴趣可以去看看完整的文章,《想修改 Android 字体,你需要先了解一下 Typeface!!!》。

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

2.1 修改Typeface 的某个默认字体

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

9a4800fb64a71d1ec9257a0bdc8b5217.png

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

8da9b160ab82bbbc502e570eb50ba764.png

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

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

2.2 在 TextView 中默认的字体

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

6796ef2d3447255869a292c65dac7c8d.png

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

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

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

5ccd898e46ee119acc32bcdcd2e33575.png

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

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

条件就是:

fontFamily ==null&& typefaceIndex != -1

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

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

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

d69089616080e1fcdf0e883340373ec2.png

三、通过反射修改字体

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

3.1 修改 Theme

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

ac927a4101fd94ad46d7f6e642c31f95.png

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

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

3.2 通过反射修改 Typeface 的字体

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

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

0217cadc755d05d46be24352ab576eec.png

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

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

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

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

c5fb2420febb3ec12ce17de1ec536133.png

3.4 验证运行结果

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

1d39e6d01815778a70dd295b5170ac65.png

【本文为51CTO专栏作者“张旸”的原创稿件,转载请通过微信公众号联系作者获取授权】

【编辑推荐】

【责任编辑:武晓燕 TEL:(010)68476606】

点赞 0

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值