經過修改 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 等等,這些都是咱們須要重寫的控件。

點贊或者分享吧~

相關文章
相關標籤/搜索