全局修改默認字體,通過反射也能做到
序
在 Android 下使用自定義字體已經是一個比較常見的需求了,最近也做了個比較深入的研究。
那么按照慣例我又要出個一篇有關 Android 修改字體相關的文章,但是寫下來發(fā)現(xiàn)內容還挺多的,所以我決定將它們拆分一下,分幾篇來詳細的講解(可能是五篇)。主要會是一些常用的替換字體的方案,***還會介紹一些全局替換的方案,當然也會包含***的 『Fonts in XML』的方案。
期待你持續(xù)關注。
本篇是本系列的第四篇,之前已經發(fā)布的文章,有興趣可以先看看。
一、前言
本文依然屬于 Android 修改字體的系列,本系列開始會介紹一些比較方便的全局修改的方案,越往后的方案可能會越好一些,但是不一定最適用你現(xiàn)在的項目。
今天介紹的就是其中的一個,使用反射的方式,修改 Typeface 中的某個字體,來達到全局替換的目的。
二、替換默認字體的思路
本文的很多預備的知識點,應該在之前的文章中就已經說清楚了,有興趣可以去看看完整的文章,《想修改 Android 字體,你需要先了解一下 Typeface!!!》。
這里為了保證邏輯完整,還是大概說一下思路。
2.1 修改Typeface 的某個默認字體
首先需要明確一點,在 Android 中,所有操作字體的動作,都會使用到 Typeface 這個類。而系統(tǒng)默認的一些字體,也會在 Typeface 被加載的時候進行初始化,因為這些步驟在它的靜態(tài)代碼塊內完成。
而這些字體都會定義成了 static final 的,所以一般我們是不能去修改它們的。
但是我們是可以使用反射的方式去修改被標記為 static final 的常量的,這個后面再將細節(jié)。
也就是說,我們只需要在初始化的實際,替換掉某個默認的字體,然后在Theme 內將默認字體字體標記為該字體,就可以達到替換的目的。
2.2 在 TextView 中默認的字體
在 TextView 的構造方法里,設置字體的方法是 setTypefaceFromAttrs() ,下面是該方法的方法簽名。
在該方法的參數(shù)中,如果 familyName 為 null 的時候,會根據(jù)傳入的 typefaceIndex 去設置對應的字體,傳入到 setTypeface() 方法中。
再來看看 TextView 的構造方法中,獲取這幾個參數(shù)的地方。在默認什么都不設置的情況下, familyName 就是為 null,而 typefaceIndex 為 -1。這兩個參數(shù)會先從 TextAppearance 中讀取屬性,再從 TextView 本身設置的 xml 屬性中讀取,后者會覆蓋前者。
可是 typefaceIndex 還會有一些其它的操作,例如 inputType 為 password 的時候,就會強行修改為 MONOSPACE。
最終,將處理后的結構,傳遞給 setTypefaceFromAttrs() 方法。
通過這些細節(jié),我們就可以了解到,是在有一些情況下,是可以保證 TextView 使用的是我們的某個被加載到 Typeface 中的默認字體的。
條件就是:
- fontFamily == null && typefaceIndex != -1
2.3 在 Theme 中,修改字體為默認字體樣式
對于一些默認的字體樣式,是可以直接在 Theme 中進行設置的,它的優(yōu)先級低于在頁面布局的 xml 中,為 TextView 設置的字體樣式,但是如果不設置,那么在 Theme 中的設置將會生效。
這個沒什么好說的,我這里用的主題就是 AppTheme,所以我在它里面修改 android:typeface 就可以了。
三、通過反射修改字體
到這里,基本的概念就已經講解清楚了,那么我們就開始實際編寫代碼來替換字體了。
3.1 修改 Theme
在 App 的主題中,修改 android:typeface 為 serif。
注意,這里隨便選了一個默認字體,實際上使用 monospace 也是可以的,只需要和后面我們替換的字體保持一致即可。
當然這里不推薦使用 monospace ,因為 TextView 本身還有一些邏輯會將 typefaceIndex 設置成 monospace,所以我們不要替換它比較好。
3.2 通過反射修改 Typeface 的字體
在 Typeface 中,是有一些被標記為 static final 的默認字體,因為上一步的 Theme 中,就是設置的 serif ,所以我們這里替換它就好了。
完整的方法非常的簡單,就是通過反射拿到 Typeface.SERIF,然后使用反射將它修改成我們需要的字體即可。
因為這里修改了 static final 的值,所以需要額外調用 setAccessible() 方法,它會修改 AccessibleObject 中的 overide 為 true,這個標記的意思,就是關閉對這個字段改寫的安全檢查,從而讓我們可以替換 static final 的字段。
3.3 在入口的地方,調用替換的方法
接下來就清晰了,我們只需要在 App 啟動的時候,調用一下 changeDefaultFont() 方法。
這里直接在 Application.onCreate() 方法中,調用即可。
3.4 驗證運行結果
這個沒什么了,直接寫個 Demo,正常使用 TextView 就可以了。

【本文為51CTO專欄作者“張旸”的原創(chuàng)稿件,轉載請通過微信公眾號聯(lián)系作者獲取授權】