全局替换字体,开源库更方便!!!

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

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

期待你持续关注。算法

本篇是本系列的第九篇,以前已经发布的文章,有兴趣能够先看看。安全

1、前言

以前已经介绍了不少种,快速、低入侵的替换全局字体的方式。可是大多数状况下,咱们须要实现的功能,必定已经有现成的实现方案。app

本文就介绍一个 Github 上,比较火的全局替换字体的开源库,差很少阅读文档加集成,一个小时全局替换字体不是梦。ide

这个开源替换字体库就是 Calligraphy:学习

https://github.com/chrisjenx/...字体

2、如何使用Calligraphy

既然是要接入开源库来全局替换字体,先来看看它能够实现的效果。gradle

/screenshot.png

接下来,咱们开始一步步集成它。ui

2.1 添加 Gradle 依赖

Calligraphy 支持 Gradle 和 jar 的接入方式,这里使用 Gradle 来接入。

/gradle-denpen.png

2.2 添加字体文档到项目内

Calligraphy 支持的文件,能够放在 assets/ 目录下,固然,咱们能够再在其中创建一个文件夹来专门的存放字体文件。

/assets-font-file.png

2.3 初始化 Calligraphy

Calligraphy 使用 CalligraphyConfig 类,来进行初始化。它须要在 App 的入口,Application.onCreate() 中调用。

/init-method.png

初始化主要是为了指定一些默认的配置,例如:默认字体、默认属性值。

2.4 替换 Context

Calligraphy 对 Activity 的 Context,进行了一次包装,须要使用它包装的 Context,才能够达到替换字体的效果。因此还须要重写 BaseActivity 中的 attachBaseContext() 方法,将其替换成 Calligraphy 为咱们提供的 Context 的包装类 CalligraphyContextWrapper。

/attach-base-context.png

2.5 使用 Calligraphy

到这里,就完成了 Calligraphy 的配置了,咱们只须要在 TextView 中,经过属性去使用它就行了,它配置的是咱们字体文件,在 assets 目录下的路径。

/text-layout-xml.png

2.6 查缺补漏

Calligraphy 使用起来仍是很方便的,而且也支持更多的配置方式,例如: Style、Theme 均可以。

具体的使用细节,你们仍是阅读文档了解更方便。

3、Calligraphy的原理

咱们使用一个开源库,固然要理解它的原理才能放心使用在商业项目上,接下来,咱们就来分析一下 Calligraphy 的实现原理,看看和以前介绍的方式,有没有什么区别。

先来看看 Calligraphy 的总体结构。

/call-path.png

能够看到,它一共须要的类很是的少,算是一个比较精简的库了,而且它并无重写 TextView ,因此应该是经过其它的方式来作到字体的替换的。

咱们先来看看在 Application 须要调用的配置类, CalligraphyConfig 的源码。

/config-methon.png

CalligraphyConfig 使用 Builder 的模式去初始化本身,能够看到这里只是设置了一些配置项,并无实际的业务逻辑。

/config-get.png

CalligraphyConfig 初始化以后,就以静态变量存储起来,供其它地方使用,是一种单例的模式,可是并无考虑线程安全的问题。

既然 CalligraphyConfig 没有实际的逻辑,那么接下去应该如何追踪重要的代码呢?

仔细观察以前配置项里,须要重写 Activity.attachBaseContext() 方法,这里会传递它重写的一个 Context 的包装类 CalligraphyContextWrapper,因此接下来咱们再看看 CalligraphyContextWrapper 的源码逻辑。

/getSystemServer.png

读了 CalligraphyContextWrapper 源码以后,你会发现它最重要的就是重写了 getSystemService() 方法,当它是 LAYOUT_INFLATER_SERVICE 的时候,将本身的 CalligraphyLayoutInflater 类,返回回去。

那么,这里的 LAYOUT_INFLATER_SERVICE 究竟是什么呢?

我想你们应该对 LayoutInflater 不陌生,从 layout-xml 加载 View 的时候,都须要用到它,相信下面这段代码,应该你们都不陌生。

/layoutinfalter-code.png

再仔细看看 LayoutInflater.from() 方法的源码。

/layoutinflalter-from.png

能够看到,这里得到 LayoutInflater 对象的时候,用到的就是 LAYOUT_INFLATER_SERVICE。

因此 CalligraphyContextWrapper.getSystemService() 方法被重写的目的,就是为了替换掉 LayoutInflater 对象,因此能够猜测,设置自定义字体的地方,就在自定义的 LayoutInflater 中。

继续查看 CalligraphyLayoutInflater 的源码,最终修改字体的逻辑,是在 CalligraphyContextWrappe 的 onViewCreatedInternal() 方法里面。

/view-create-interval.png

它会取出咱们自定义属性上设置的值,而后设置到初始化好的 TextView 上去。

4、Calligraphy 小结

到此就完成了 Calligraphy 的主要逻辑追踪,几个核心技术点:

  1. Calligraphy 不须要重写 TextView 之类的控件。
  2. Calligraphy 重写了 LayoutInflater 。
  3. Calligraphy 在 attachBaseContext() 方法中,替换掉 ContextWrapper。
  4. 又经过自定义的 ContextWrapper 的 getSystemService() 方法,将 LayoutInflater 替换成库里重写的 CalligraphyLayoutInflater。
  5. 在 CalligraphyLayoutInflater 中,拦截咱们须要的 TextView 和其子类,对它们的字体替换成咱们设置的字体。

固然,实际上,开源库之因此能够流传的比较广,它还作了更多的细节处理,可是咱们通常分析开源库,只须要关心主线逻辑就能够了。

总体来讲 Calligraphy 没有什么大毛病,能够放心使用,固然若是你用了一些一样依赖此原理的第三方库,可能会有冲突,这个就只能具体问题具体分析了。

今天在承香墨影公众号的后台,回复『成长』。我会送你一些我整理的学习资料,包含:Android反编译、算法。Web项目源码。

推荐阅读:

点赞或者分享吧~

相关文章
相关标签/搜索