经过修改 LayoutInflater,全局替换字体!!!

/WechatIMG13.jpeg
/WechatIMG13.jpeg

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

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

期待你持续关注。字体

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

1、前言

上一篇讲解了经过替换 AppCompatDelegate 来达到替换控件的目的,从而替换成咱们须要的可设置自定义字体的控件,来达到替换字体的目的。code

如今大多数人应该看出来了,到最后实现的目标就是如何快速、低入侵的替换全局控件,而后对这些控件进行重写,就能够达到咱们不少的目的。换字体只是这其中的一种应用,还有其它的,例如:换肤、无痕埋点等等,都是有可借鉴的地方的。cdn

本文再介绍一种方式,经过 LayoutInflaterCompat.setFactory() 替换掉 LayoutInflaterFactory 或者 LayoutInflater.Factory2,来达到咱们替换控件的目的,从而实现全局字体的替换。xml

接下来开始介绍全部的技术细节。对象

2、setFactory()

2.1 setFactory() 的技术原理

对你们而言,LayoutInflater 应该是不陌生的,全部须要动态加载 layout-xml 中的 View 的地方都须要用到它的 inflater() 方法,例如:ListView、RecyclerView。blog

而本文须要用到的是它另外两个 Api 方法,setFactory()setFactory2()。它们的方法签名以下。继承

/setFactory.png
/setFactory.png

这两个方法分别接收 Factory 和 Factory2 ,它们两个都是 Interface。而且这两个方法的功能也是相似的。只是 setFactory2() 是在 Api Level 11 以后引入的,使用那个取决于项目的 minSdkVersion。

不过通常而言,咱们也不须要直接使用它。咱们须要只用 Support.v4 包中,为咱们提供的 LayoutInflaterCompat 这个兼容类来作处理。和全部的兼容类同样,它其中会有一个 IMPL 的变量,会根据不一样的 Api Level 初始化不一样的实例。

/compatImpl.png
/compatImpl.png

能够看到,这里只对 Api Level 21 做为一个分界,去处理逻辑,其中会有不一样的实现,这里有兴趣能够一探究竟,有时间会单独出一篇文章来说解,这里就再也不深刻了。

这里,咱们须要用到 LayoutInflaterCompat.setFactory() 方法,它实际上已经被标记为 @Deprecated 了,通常推荐咱们使用 LayoutInflaterCompat.setFactory2(),可是它们的功能是一致的,这里就不纠结这些细节了。

/impl-setfactory.png
/impl-setfactory.png

能够看到,setFactory() 接收一个 LayoutInflaterFactory 的对象,它其实是一个接口,须要咱们实现其中的 onCreateView() 方法。

/LayoutFactory.png
/LayoutFactory.png

咱们这里主要的功能,就在于实现 onCreateView() 方法,将咱们须要的控件在这个方法中替换掉。

2.2 举个例子

对着源码说太干了。下面我举个实际的例子,相信就能够说明问题了。

首先我新建一个 Activity,在 super.onCreate() 以前,经过 LayoutInflaterCompat 从新设置 Factory,在关键地方打印好 Log。

/setfactory-javacode.png
/setfactory-javacode.png

再声明一个布局,让它去显示 layout-XML 布局,层级很简单,就是一个 LinearLayout 中间包含了一个 TextView。

而后,咱们运行起来看看输出的 Log ,这里撇开了 DecorView 等这些布局的打印,只看关键部分。

/setFactory-log.png
/setFactory-log.png

从 Log 输出能够看出,实际上,你全部布局的控件,都会通过 LayoutInflaterFactory.onCreateView() 方法走一遍,去实现初始化的过程,在其中能够有效的分辨出是什么控件,以及它有什么属性。

而且 onCreateView() 方法的返回值,就是一个 View,若是要替换该 View,能够在此处将其初始化后返回回去便可。

3、利用 LayoutInflater 替换字体

既然原理都清楚了,那么咱们接下来就开始实际操做一下,如何经过替换 LayoutInflaterFactory 来达到替换控件,从而达到替换字体的目的。

首先,定义一个 Activity 为基类,其中在 super..onCreate() 方法以前,调用 LayoutInflaterCompat.setFactory() ,而后将它的替换为 咱们本身定义的 CustomFontCompatDelegate 类。

/demo-activitycode.png
/demo-activitycode.png

CustomFontCompatDelegate 的实现,也很是的简单,只须要在它的 onCreateView() 方法中,替换掉 TextView 就能够。

/demo-delegate-code.png
/demo-delegate-code.png

其实,全部替换字体的逻辑,都在 FontTextView 中,接下来咱们再看看 FontTextView 的逻辑。

/fontTextView.png
/fontTextView.png

能够看到,在 FontTextView 中,直接完整的将字体替换成咱们在 assets 目录下存放的 custom_font.ttf 字体文件。

到这里就完成了基本的功能,咱们接下来看看如何使用它。

只须要使用一个 Activity ,继承咱们刚才实现的 CustomFontActivity,而后写一个简单的布局,其中有三个 TextView。

/demo-activityxml.png
/demo-activityxml.png

最后,咱们再来看看运行后的效果。

/f-fontimage.png
/f-fontimage.png

4、小结

到这里基本上就介绍清楚如何经过 LayoutInflaterCompat.setFactory() 去替换 Factory 这个接口,达到咱们替换控件的目的,从而完美的替换全局的字体。

可是实际开发过程当中,依然须要考虑全部能够显示文字的控件,例如:TextView、EditText、Button 等等,这些都是咱们须要重写的控件。

点赞或者分享吧~

相关文章
相关标签/搜索