通過修改 LayoutInflater,全局替換字體!!!


/WechatIMG13.jpeg

在 Android 下使用自定義字體已經是一個比較常見的需求了,最近也做了個比較深入的研究。

那么按照慣例我又要出個一篇有關 Android 修改字體相關的文章,但是寫下來發現內容還挺多的,所以我決定將它們拆分一下,分幾篇來詳細的講解。主要會是一些常用的替換字體的方案,最后還會介紹一些全局替換的方案,當然也會包含最新的 『Fonts in XML』的方案。

期待你持續關注。

本篇是本系列的第六篇,之前已經發布的文章,有興趣可以先看看。

一、前言

上一篇講解了通過替換 AppCompatDelegate 來達到替換控件的目的,從而替換成我們需要的可設置自定義字體的控件,來達到替換字體的目的。

現在大多數人應該看出來了,到最后實現的目標就是如何快速、低入侵的替換全局控件,然后對這些控件進行重寫,就可以達到我們很多的目的。換字體只是這其中的一種應用,還有其它的,例如:換膚、無痕埋點等等,都是有可借鑒的地方的。

本文再介紹一種方式,通過 LayoutInflaterCompat.setFactory() 替換掉 LayoutInflaterFactory 或者 LayoutInflater.Factory2,來達到我們替換控件的目的,從而實現全局字體的替換。

接下來開始介紹所有的技術細節。

二、setFactory()

2.1 setFactory() 的技術原理

對大家而言,LayoutInflater 應該是不陌生的,所有需要動態加載 layout-xml 中的 View 的地方都需要用到它的 inflater() 方法,例如:ListView、RecyclerView。

而本文需要用到的是它另外兩個 Api 方法,setFactory()setFactory2()。它們的方法簽名如下。

/setFactory.png

這兩個方法分別接收 Factory 和 Factory2 ,它們兩個都是 Interface。並且這兩個方法的功能也是類似的。只是 setFactory2() 是在 Api Level 11 之后引入的,使用那個取決於項目的 minSdkVersion。

不過一般而言,我們也不需要直接使用它。我們需要只用 Support.v4 包中,為我們提供的 LayoutInflaterCompat 這個兼容類來做處理。和所有的兼容類一樣,它其中會有一個 IMPL 的變量,會根據不同的 Api Level 初始化不同的實例。

/compatImpl.png

可以看到,這里只對 Api Level 21 作為一個分界,去處理邏輯,其中會有不同的實現,這里有興趣可以一探究竟,有時間會單獨出一篇文章來講解,這里就不再深入了。

這里,我們需要用到 LayoutInflaterCompat.setFactory() 方法,它實際上已經被標記為 @Deprecated 了,一般推薦我們使用 LayoutInflaterCompat.setFactory2(),但是它們的功能是一致的,這里就不糾結這些細節了。

/impl-setfactory.png

可以看到,setFactory() 接收一個 LayoutInflaterFactory 的對象,它實際上是一個接口,需要我們實現其中的 onCreateView() 方法。

/LayoutFactory.png

我們這里主要的功能,就在於實現 onCreateView() 方法,將我們需要的控件在這個方法中替換掉。

2.2 舉個例子

對着源碼說太干了。下面我舉個實際的例子,相信就可以說明問題了。

首先我新建一個 Activity,在 super.onCreate() 之前,通過 LayoutInflaterCompat 重新設置 Factory,在關鍵地方打印好 Log。

/setfactory-javacode.png

再聲明一個布局,讓它去顯示 layout-XML 布局,層級很簡單,就是一個 LinearLayout 中間包含了一個 TextView。

然后,我們運行起來看看輸出的 Log ,這里撇開了 DecorView 等這些布局的打印,只看關鍵部分。

/setFactory-log.png

從 Log 輸出可以看出,實際上,你所有布局的控件,都會經過 LayoutInflaterFactory.onCreateView() 方法走一遍,去實現初始化的過程,在其中可以有效的分辨出是什么控件,以及它有什么屬性。

並且 onCreateView() 方法的返回值,就是一個 View,如果要替換該 View,可以在此處將其初始化后返回回去即可。

三、利用 LayoutInflater 替換字體

既然原理都清楚了,那么我們接下來就開始實際操作一下,如何通過替換 LayoutInflaterFactory 來達到替換控件,從而達到替換字體的目的。

首先,定義一個 Activity 為基類,其中在 super..onCreate() 方法之前,調用 LayoutInflaterCompat.setFactory() ,然后將它的替換為 我們自己定義的 CustomFontCompatDelegate 類。

/demo-activitycode.png

CustomFontCompatDelegate 的實現,也非常的簡單,只需要在它的 onCreateView() 方法中,替換掉 TextView 就可以。

/demo-delegate-code.png

其實,所有替換字體的邏輯,都在 FontTextView 中,接下來我們再看看 FontTextView 的邏輯。

/fontTextView.png

可以看到,在 FontTextView 中,直接完整的將字體替換成我們在 assets 目錄下存放的 custom_font.ttf 字體文件。

到這里就完成了基本的功能,我們接下來看看如何使用它。

只需要使用一個 Activity ,繼承我們剛才實現的 CustomFontActivity,然后寫一個簡單的布局,其中有三個 TextView。

/demo-activityxml.png

最后,我們再來看看運行后的效果。

/f-fontimage.png

四、小結

到這里基本上就介紹清楚如何通過 LayoutInflaterCompat.setFactory() 去替換 Factory 這個接口,達到我們替換控件的目的,從而完美的替換全局的字體。

但是實際開發過程中,依然需要考慮所有可以顯示文字的控件,例如:TextView、EditText、Button 等等,這些都是我們需要重寫的控件。

點贊或者分享吧~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM