全局修改默認字體,經過反射也能作到

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

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

期待你持續關注。app

本篇是本系列的第四篇,以前已經發布的文章,有興趣能夠先看看。ide

1、前言

本文依然屬於 Android 修改字體的系列,本系列開始會介紹一些比較方便的全局修改的方案,越日後的方案可能會越好一些,可是不必定最適用你如今的項目。佈局

今天介紹的就是其中的一個,使用反射的方式,修改 Typeface 中的某個字體,來達到全局替換的目的。字體

2、替換默認字體的思路

本文的不少預備的知識點,應該在以前的文章中就已經說清楚了,有興趣能夠去看看完整的文章,《》。spa

這裏爲了保證邏輯完整,仍是大概說一下思路。3d

2.1 修改Typeface 的某個默認字體

首先須要明確一點,在 Android 中,全部操做字體的動做,都會使用到 Typeface 這個類。而系統默認的一些字體,也會在 Typeface 被加載的時候進行初始化,由於這些步驟在它的靜態代碼塊內完成。code

/f-init.png

而這些字體都會定義成了 static final 的,因此通常咱們是不能去修改它們的。xml

/f-staticfinal.png

可是咱們是可使用反射的方式去修改被標記爲 static final 的常量的,這個後面再將細節。

也就是說,咱們只須要在初始化的實際,替換掉某個默認的字體,而後在Theme 內將默認字體字體標記爲該字體,就能夠達到替換的目的。

2.2 在 TextView 中默認的字體

在 TextView 的構造方法裏,設置字體的方法是 setTypefaceFromAttrs() ,下面是該方法的方法簽名。

/f-setAttr.png

在該方法的參數中,若是 familyName 爲 null 的時候,會根據傳入的 typefaceIndex 去設置對應的字體,傳入到 setTypeface() 方法中。

再來看看 TextView 的構造方法中,獲取這幾個參數的地方。在默認什麼都不設置的狀況下, familyName 就是爲 null,而 typefaceIndex 爲 -1。這兩個參數會先從 TextAppearance 中讀取屬性,再從 TextView 自己設置的 xml 屬性中讀取,後者會覆蓋前者。

但是 typefaceIndex 還會有一些其它的操做,例如 inputType 爲 password 的時候,就會強行修改成 MONOSPACE。

/f-getAttr.png

最終,將處理後的結構,傳遞給 setTypefaceFromAttrs() 方法。

經過這些細節,咱們就能夠了解到,是在有一些狀況下,是能夠保證 TextView 使用的是咱們的某個被加載到 Typeface 中的默認字體的。

條件就是:

fontFamily == null && typefaceIndex != -1

2.3 在 Theme 中,修改字體爲默認字體樣式

對於一些默認的字體樣式,是能夠直接在 Theme 中進行設置的,它的優先級低於在頁面佈局的 xml 中,爲 TextView 設置的字體樣式,可是若是不設置,那麼在 Theme 中的設置將會生效。

這個沒什麼好說的,我這裏用的主題就是 AppTheme,因此我在它裏面修改 android:typeface 就能夠了。

/f-theme.png

3、經過反射修改字體

到這裏,基本的概念就已經講解清楚了,那麼咱們就開始實際編寫代碼來替換字體了。

3.1 修改 Theme

在 App 的主題中,修改 android:typeface 爲 serif。

/f-theme.png

注意,這裏隨便選了一個默認字體,實際上使用 monospace 也是能夠的,只須要和後面咱們替換的字體保持一致便可。

固然這裏不推薦使用 monospace ,由於 TextView 自己還有一些邏輯會將 typefaceIndex 設置成 monospace,因此咱們不要替換它比較好。

3.2 經過反射修改 Typeface 的字體

在 Typeface 中,是有一些被標記爲 static final 的默認字體,由於上一步的 Theme 中,就是設置的 serif ,因此咱們這裏替換它就行了。

完整的方法很是的簡單,就是經過反射拿到 Typeface.SERIF,而後使用反射將它修改爲咱們須要的字體便可。

/f-replace.png

由於這裏修改了 static final 的值,因此須要額外調用 setAccessible() 方法,它會修改 AccessibleObject 中的 overide 爲 true,這個標記的意思,就是關閉對這個字段改寫的安全檢查,從而讓咱們能夠替換 static final 的字段。

3.3 在入口的地方,調用替換的方法

接下來就清晰了,咱們只須要在 App 啓動的時候,調用一下 changeDefaultFont() 方法。

這裏直接在 Application.onCreate() 方法中,調用便可。

/f-myapp.png

3.4 驗證運行結果

這個沒什麼了,直接寫個 Demo,正常使用 TextView 就能夠了。

/f-fontimage.png

公衆號二維碼.jpg

相關文章
相關標籤/搜索