在 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項目源碼。
推薦閱讀:
點贊或者分享吧~