Android中以粗暴的方式替換全局字體
序
在 Android 下使用自定義字體已經(jīng)是一個(gè)比較常見的需求了,最近也做了個(gè)比較深入的研究。
那么按照慣例我又要出個(gè)一篇有關(guān) Android 修改字體相關(guān)的文章,但是寫下來(lái)發(fā)現(xiàn)內(nèi)容還挺多的,所以我決定將它們拆分一下,分幾篇來(lái)詳細(xì)的講解(可能是五篇)。主要會(huì)是一些常用的替換字體的方案,***還會(huì)介紹一些全局替換的方案,當(dāng)然也會(huì)包含***的 『Fonts in XML』的方案。
期待你持續(xù)關(guān)注。
本篇是本系列的第二篇,之前已經(jīng)發(fā)布的文章,有興趣可以先看看。
修改字體需要了解 Typeface 的所有細(xì)節(jié)
一、前言
前面已經(jīng)分析了修改字體的所有細(xì)節(jié),以及與修改字體相關(guān)的 Typeface 類,接下來(lái)就開始討論如何修改全局字體。
本篇會(huì)先介紹兩種比較粗暴的方式來(lái)修改全局的字體。
二、自定義控件
在開始一個(gè)新的項(xiàng)目的時(shí)候,一般習(xí)慣好點(diǎn)的都會(huì)定義一個(gè) BaseActivity 和 BaseFragment 來(lái)作為頁(yè)面的基類,這樣可以方便我們?cè)谥蟮臅r(shí)候,對(duì)所有頁(yè)面增加一些統(tǒng)一的邏輯。
不過(guò)應(yīng)該不會(huì)有人提前想到要給所有的控件,提前定義一個(gè)自定義的控件實(shí)現(xiàn)。
但是如果在開發(fā)的初期,就已經(jīng)考慮到字體需要修改的情況的話,是可以重寫一些字體顯示相關(guān)的控件。來(lái)達(dá)到全局替換字體的作用的。
Android 中,最常用的用來(lái)顯示字體的控件,就是 TextView,這里就重寫一個(gè) TextView 來(lái)達(dá)到替換字體的效果。
在 TextView 中,可以通過(guò) setTypeface() 方法,為 TextView 設(shè)置一個(gè)字體,setTypeface() 方法有兩個(gè)重載方法,無(wú)非就是多傳遞了一個(gè)需要設(shè)置的 textStyle,用來(lái)標(biāo)記粗體和斜體。
其實(shí)最終都是調(diào)用一個(gè)參數(shù)的 setTypeface(,它才是設(shè)置的關(guān)鍵。
可以看到,設(shè)置字體實(shí)際上是操作的 mTextPaint,mTextPaint 是 TextPaint 類的對(duì)象,直接繼承自 Paint,就是一個(gè)用來(lái)繪制文字的畫筆。
那么,我們就可以直接自定義一個(gè) TextView ,在構(gòu)造函數(shù)中,通過(guò) setTypeface() 方法,來(lái)修改 TextView 的字體。
主要代碼如下:
注意,這里還需要考慮在布局中,為我們?cè)O(shè)定的 FontTextView 設(shè)置的 textStyle 屬性,可能是粗體或者斜體。
通常設(shè)計(jì)師為了考慮 App 的 UI 統(tǒng)一性和協(xié)調(diào)性,一般都會(huì)選用一個(gè)字體,所以將需要替換的字體封裝在 FontTextView 中,也沒(méi)有什么大的問(wèn)題。
那么來(lái)驗(yàn)證看看實(shí)現(xiàn)出來(lái)的效果,這里專門選擇了一個(gè)比較特殊的字體。在布局 xml 文件中,添加三個(gè) FontTextView。
再來(lái)看看運(yùn)行的效果。
這里也考慮了在布局中設(shè)置的 textStyle,并且一個(gè)已經(jīng)比較傾斜的字體,使用 italic 標(biāo)記之后,更傾斜了。
這個(gè)方法,如果在開發(fā)初期,還可以接受,無(wú)非就是寫布局的時(shí)候,需要注意使用自定義的控件,同時(shí)還除了 TextView ,還需要重寫 Button、EditText 等一系列需要顯示文字的控件,說(shuō)到底還是有點(diǎn)麻煩的。
而且如果是在一個(gè)已經(jīng)成熟的項(xiàng)目上再使用這種方案,改動(dòng)起來(lái)還是很費(fèi)勁的,基本上就是一通文本替換,改動(dòng)會(huì)比較大一些。
三、遍歷 ViewTree
在 Android 中,用于顯示文本的控件,都是直接或者間接集成自 TextView 的,那么我們只需要找一個(gè)合適的時(shí)機(jī),遍歷布局的 ViewTree,將其中所有 TextView 的子類都獲取出來(lái),然后批量修改它們的字體,同樣也可以達(dá)到全局替換的效果。
在這個(gè) replaceCustomFont() 的方法里,回去判斷是否繼承自 TextView,如果是就替換字體。如果不是,再判斷是否是一個(gè) ViewGroup,如果是的話,從其內(nèi)取出所有的子 View,再遞歸調(diào)用 replaceCustomFont() 方法。
通常,為了在合適的時(shí)機(jī)修改字體,我們可以將這個(gè)方法加在 Activity.onCreate() 方法,或者 Fragment.onCreateView() 方法的后面,修改的地方,相對(duì)少一些,不過(guò)還需要考慮 ListView、RecyclverView 這種動(dòng)態(tài)生成 View 的邏輯,也需要注意不能遺漏。
舉個(gè)例子,寫一個(gè)布局,在 Activity.onCreate() 方法中,調(diào)用 replaceCustomFont() 方法。
***展現(xiàn)的效果如下。
使用這種方式,優(yōu)點(diǎn)是,不需要修改 XML 布局,不需要重寫多個(gè)控件。只需要在 Inflater View 的之后,調(diào)用一下 replaceCustomFont() 方法即可。
缺點(diǎn)也非常的明顯,每個(gè)頁(yè)面都需要修改,有動(dòng)態(tài)加載 View 的地方可能會(huì)被遺漏,改動(dòng)相比較之前的方案,稍微少一點(diǎn)。并且違背了組件的設(shè)計(jì)原則,實(shí)現(xiàn)方式也略顯粗暴。同時(shí)它每次都會(huì)遞歸遍歷 ViewTree,性能上多少都會(huì)有點(diǎn)影響。
四、小結(jié)
本文介紹的幾個(gè)辦法,在實(shí)際開發(fā)中,可能也用不上。不過(guò)不影響我們了解這樣的方法。
【本文為51CTO專欄作者“張旸”的原創(chuàng)稿件,轉(zhuǎn)載請(qǐng)通過(guò)微信公眾號(hào)聯(lián)系作者獲取授權(quán)】