在 Android 下使用自定义字体已是一个比较常见的需求了,最近也作了个比较深刻的研究。git
那么按照惯例我又要出个一篇有关 Android 修改字体相关的文章,可是写下来发现内容还挺多的,因此我决定将它们拆分一下,分几篇来详细的讲解。主要会是一些经常使用的替换字体的方案,最后还会介绍一些全局替换的方案,固然也会包含最新的 『Fonts in XML』的方案。github
期待你持续关注。算法
本篇是本系列的第九篇,以前已经发布的文章,有兴趣能够先看看。安全
以前已经介绍了不少种,快速、低入侵的替换全局字体的方式。可是大多数状况下,咱们须要实现的功能,必定已经有现成的实现方案。app
本文就介绍一个 Github 上,比较火的全局替换字体的开源库,差很少阅读文档加集成,一个小时全局替换字体不是梦。ide
这个开源替换字体库就是 Calligraphy:学习
既然是要接入开源库来全局替换字体,先来看看它能够实现的效果。gradle
接下来,咱们开始一步步集成它。ui
Calligraphy 支持 Gradle 和 jar 的接入方式,这里使用 Gradle 来接入。
Calligraphy 支持的文件,能够放在 assets/
目录下,固然,咱们能够再在其中创建一个文件夹来专门的存放字体文件。
Calligraphy 使用 CalligraphyConfig 类,来进行初始化。它须要在 App 的入口,Application.onCreate()
中调用。
初始化主要是为了指定一些默认的配置,例如:默认字体、默认属性值。
Calligraphy 对 Activity 的 Context,进行了一次包装,须要使用它包装的 Context,才能够达到替换字体的效果。因此还须要重写 BaseActivity 中的 attachBaseContext()
方法,将其替换成 Calligraphy 为咱们提供的 Context 的包装类 CalligraphyContextWrapper。
到这里,就完成了 Calligraphy 的配置了,咱们只须要在 TextView 中,经过属性去使用它就行了,它配置的是咱们字体文件,在 assets 目录下的路径。
Calligraphy 使用起来仍是很方便的,而且也支持更多的配置方式,例如: Style、Theme 均可以。
具体的使用细节,你们仍是阅读文档了解更方便。
咱们使用一个开源库,固然要理解它的原理才能放心使用在商业项目上,接下来,咱们就来分析一下 Calligraphy 的实现原理,看看和以前介绍的方式,有没有什么区别。
先来看看 Calligraphy 的总体结构。
能够看到,它一共须要的类很是的少,算是一个比较精简的库了,而且它并无重写 TextView ,因此应该是经过其它的方式来作到字体的替换的。
咱们先来看看在 Application 须要调用的配置类, CalligraphyConfig 的源码。
CalligraphyConfig 使用 Builder 的模式去初始化本身,能够看到这里只是设置了一些配置项,并无实际的业务逻辑。
CalligraphyConfig 初始化以后,就以静态变量存储起来,供其它地方使用,是一种单例的模式,可是并无考虑线程安全的问题。
既然 CalligraphyConfig 没有实际的逻辑,那么接下去应该如何追踪重要的代码呢?
仔细观察以前配置项里,须要重写 Activity.attachBaseContext()
方法,这里会传递它重写的一个 Context 的包装类 CalligraphyContextWrapper,因此接下来咱们再看看 CalligraphyContextWrapper 的源码逻辑。
读了 CalligraphyContextWrapper 源码以后,你会发现它最重要的就是重写了 getSystemService()
方法,当它是 LAYOUT_INFLATER_SERVICE 的时候,将本身的 CalligraphyLayoutInflater 类,返回回去。
那么,这里的 LAYOUT_INFLATER_SERVICE 究竟是什么呢?
我想你们应该对 LayoutInflater 不陌生,从 layout-xml 加载 View 的时候,都须要用到它,相信下面这段代码,应该你们都不陌生。
再仔细看看 LayoutInflater.from()
方法的源码。
能够看到,这里得到 LayoutInflater 对象的时候,用到的就是 LAYOUT_INFLATER_SERVICE。
因此 CalligraphyContextWrapper.getSystemService() 方法被重写的目的,就是为了替换掉 LayoutInflater 对象,因此能够猜测,设置自定义字体的地方,就在自定义的 LayoutInflater 中。
继续查看 CalligraphyLayoutInflater 的源码,最终修改字体的逻辑,是在 CalligraphyContextWrappe 的 onViewCreatedInternal()
方法里面。
它会取出咱们自定义属性上设置的值,而后设置到初始化好的 TextView 上去。
到此就完成了 Calligraphy 的主要逻辑追踪,几个核心技术点:
attachBaseContext()
方法中,替换掉 ContextWrapper。getSystemService()
方法,将 LayoutInflater 替换成库里重写的 CalligraphyLayoutInflater。固然,实际上,开源库之因此能够流传的比较广,它还作了更多的细节处理,可是咱们通常分析开源库,只须要关心主线逻辑就能够了。
总体来讲 Calligraphy 没有什么大毛病,能够放心使用,固然若是你用了一些一样依赖此原理的第三方库,可能会有冲突,这个就只能具体问题具体分析了。
今天在承香墨影公众号的后台,回复『成长』。我会送你一些我整理的学习资料,包含:Android反编译、算法。Web项目源码。
推荐阅读:
点赞或者分享吧~