當(dāng)你在設(shè)置里修改字體大小的時候,到底在修改什么

版權(quán)聲明:

本賬號發(fā)布文章均來自公眾號,承香墨影(cxmyDev),版權(quán)歸承香墨影所有。

每周會統(tǒng)一更新到這里,如果喜歡,可關(guān)注公眾號獲取最新文章。

未經(jīng)允許,不得轉(zhuǎn)載。

一、設(shè)定字體,該用 sp 還是 dp

對于 Android 開發(fā)而言,在開始學(xué)習(xí)的階段,就已經(jīng)被告知,為了達到更好的 UI 適配,應(yīng)該使用和像素(px)的無關(guān)的一些相對尺寸來進行布局。

  • View 的尺寸和距離,使用 dp 為單位。
  • 字體的大小,使用 sp 為單位。

雖然官方推薦使用 sp 為單位設(shè)定字體的尺寸,但是如果你依然堅定的使用 dp 來設(shè)置字體的尺寸,常規(guī)情況下,你會發(fā)現(xiàn)其實它們并沒有什么區(qū)別。

寫個 Demo 來驗證一下,布局代碼如下:

/sp-xml.png

這里分別用了兩個 TextView,并分別使用 dp 和 sp 設(shè)定了它的尺寸,最后跟隨一個 View,它的尺寸和 TextView 的字體同大,來做一個標(biāo)記。

/sp-demorun.png

可以看到,它們的文字是等大的,并且一個中文的寬度,正好是藍色的 View 的寬度。

看樣子,sp 和 dp 在顯示上完全是沒有區(qū)別的。

而當(dāng)我們在設(shè)置頁面,設(shè)置了字體的大小之后,這一切就不一樣了。

/sp-setting.png

這里,將字體調(diào)到最大,再來看看剛才 Demo 的顯示效果。

/sp-demorun2.png

能明顯看到,使用 sp 為單位設(shè)定的字體,已經(jīng)被變大了,而使用 dp 為單位設(shè)定的字體,依然保持原樣的尺寸。

由此,可以簡單的得出結(jié)論:

使用 sp 為單位標(biāo)記字體,會隨著系統(tǒng)的字體大小而改變。而使用 dp 則不會。

而這種設(shè)定你也可以在官方文檔中找到對應(yīng)的描述。

/sp-doc.png

大概的意思,就是說 sp 除了受到 density(屏幕密度) 的影響之外,還受到用戶設(shè)定的字體大小影響,所以一般推薦使用 sp 來設(shè)定字體,讓字體的顯示效果交給用戶設(shè)定。

有興趣可以看看文檔:

https://developer.android.com/guide/topics/resources/more-resources.html#Dimension

既然已經(jīng)有這樣的結(jié)論了,那么就可以清晰認識到:

推薦使用 sp 來作為字體單位,但是如果有需要字體尺寸不跟隨系統(tǒng)字體尺寸變動,則可以使用 dp 來作為字體單位。

二、sp 到底是怎么被改變的

到這里就已經(jīng)了解清楚 sp 和 dp 的區(qū)別了,但是我們應(yīng)該不滿足于此,接下來再來研究一下,sp 是在何時被改變的吧。

一切的答案都在源碼里。

先從設(shè)定文字大小的入口,看看 TextView.setTextSize() 方法。

/sp-settextsize.png

setTextSize() 是有兩個重載方法的,如果不設(shè)定 TypedValue 的話,它會默認認為你設(shè)定的是一個 TypedValue.COMPLEX_UNIT_SP 值,表示以 sp 為單位。

這里最終會使用 TypedValue.applyDimension() 方法,計算出一個值,傳遞給 setRawTextSize() 方法,在本文中 applyDimension() 方法是如何計算尺寸的。

/sp-dims.png

當(dāng) unit 為 COMPLEX_UNIT_SP 的使用,是使用 DisplayMetrics.scaledDensity 為一個比例,參與計算的。

接下來,我們的重點就是找到是什么決定 scaleDensity 的值,看看 scaleDensity。

/sp-scaledensity.png

這里的注釋也說明了,scaleDensity 不僅僅受設(shè)備的 density 影響,還受用戶設(shè)定的字體尺寸影響。

DisplayMetrics.scaleDensity 在 DisplayMetrics 類中,并沒有初始化的地方,可它是一個 public 的字段,也就是說可以被外部賦值初始化。

真正為 DisplayMetrics 中,各個字段賦值的地方,在 ResourcesImpl 中,有一個 updateConfiguration() 方法,在其中,就有對 scaleDensity 進行初始化的邏輯。

/sp-resource.png

可以看到,這里又引入了一個新的計算因子,fontScale。而從 Configuration 的源碼又了解到,fontScale 默認值為 1 ,這也就是為什么通常情況下,density 和 scaleDensity 的值是相等的,它們分別影響了 dp 和 sp 最終渲染出來的像素尺寸。

在 Display.java 的源碼中,可以找到修改 fontScale 的過程。

/sp-changescale.png

正常情況下,會有三種不同的比例,0.75f、1.25f、1.0f ,而這里的取值范圍,完全是廠商決定的,就像在本文開頭距離的設(shè)備截圖中,可以看到有四個選項。

fontScale 被作為了一個系統(tǒng)的設(shè)置項,被存儲起來,使用 Settings.System 來進行管理,它的 Key 是 Setting.System.FONT_SCALE

而 FONT_SCALE 最終是由 ActivityManagerService 來負責(zé)取出,并且賦值到 Configuration 中的。

/sp-as.png

三、獲取用戶字體的改變

到這里,本文的所有內(nèi)容,就形成了閉環(huán),了解清楚 sp 尺寸的來龍去脈。

而在開發(fā)過程中,如果想要知道當(dāng)前環(huán)境下,用戶是否改變過字體大小,可以直接從 Configuration 中獲取即可。

/sp-getfontscale.png

只要不為 1 ,就是表示用戶有改變。

公眾號二維碼.jpg

點贊或者分享吧~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容