在手機系統(tǒng)設(shè)置中桩卵,若是修改了字體大小验靡,會影響 app 內(nèi)字體顯示,導(dǎo)致布局混亂不齊雏节。有兩種方法胜嗓,一般推薦第二種方法。
方法一:
字體大小單位使用 dp钩乍,而不是使用 sp辞州。注意在 java 代碼中需要用 dp 方式顯示。默認(rèn)是使用 sp件蚕。
tv.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 30); // 注意K锛肌产禾!是TypedValue.COMPLEX_UNIT_DIP
為什么呢?我們剛學(xué) android 時牵啦,不是說字體大小用 sp亚情,布局大小用 dp 嗎?
別急哈雏,下面看看字體設(shè)置的源碼:
public static float applyDimension(int unit, float value,
DisplayMetrics metrics){
switch (unit) {
case COMPLEX_UNIT_PX:
return value;
case COMPLEX_UNIT_DIP:
return value * metrics.density;
case COMPLEX_UNIT_SP:
return value * metrics.scaledDensity;
case COMPLEX_UNIT_PT:
return value * metrics.xdpi * (1.0f/72);
case COMPLEX_UNIT_IN:
return value * metrics.xdpi;
case COMPLEX_UNIT_MM:
return value * metrics.xdpi * (1.0f/25.4f);
}
return 0;
}
可以發(fā)現(xiàn)楞件,dp 和 sp 的區(qū)別就是density
和scaledDensity
。下面再看看兩者的區(qū)別:
/**
* The logical density of the display. This is a scaling factor for the
* Density Independent Pixel unit, where one DIP is one pixel on an
* approximately 160 dpi screen (for example a 240x320, 1.5"x2" screen),
* providing the baseline of the system's display. Thus on a 160dpi screen
* this density value will be 1; on a 120 dpi screen it would be .75; etc.
*
* <p>This value does not exactly follow the real screen size (as given by
* {@link #xdpi} and {@link #ydpi}, but rather is used to scale the size of
* the overall UI in steps based on gross changes in the display dpi. For
* example, a 240x320 screen will have a density of 1 even if its width is
* 1.8", 1.3", etc. However, if the screen resolution is increased to
* 320x480 but the screen size remained 1.5"x2" then the density would be
* increased (probably to 1.5).
*
* @see #DENSITY_DEFAULT
*/
public float density;
/**
* A scaling factor for fonts displayed on the display. This is the same
* as {@link #density}, except that it may be adjusted in smaller
* increments at runtime based on a user preference for the font size.
*/
public float scaledDensity;
簡單說裳瘪,就是density
不會受到用戶配置的影響土浸,而scaledDensity
除了會受到用戶配置的影響,其它方面是跟density
一致的彭羹。
終于真相大白黄伊!因此使用 sp 單位時字體大小會受到用戶配置系統(tǒng)字體的影響。
方法二:(推薦)
在 activity 內(nèi)重寫getResources
方法派殷,如此在 xml 和 java 代碼使用 sp 字體單位都是正常的还最。一般在BaseActivity
內(nèi)重寫。
/**
* 設(shè)置 app 字體不隨系統(tǒng)字體設(shè)置改變
*/
@Override
public Resources getResources() {
Resources res = super.getResources();
if (res != null) {
Configuration config = res.getConfiguration();
if (config != null && config.fontScale != 1.0f) {
config.fontScale = 1.0f;
res.updateConfiguration(config, res.getDisplayMetrics());
}
}
return res;
}
注意毡惜!網(wǎng)上很多地方寫著使用config.setToDefaults();
拓轻,實際上除了影響 app 內(nèi)字體大小,還會影響很多地方的屬性值经伙。我們來看一下源碼:
/**
* Set this object to the system defaults.
*/
public void setToDefaults() {
fontScale = 1;
mcc = mnc = 0;
mLocaleList = LocaleList.getEmptyLocaleList();
locale = null;
userSetLocale = false;
touchscreen = TOUCHSCREEN_UNDEFINED;
keyboard = KEYBOARD_UNDEFINED;
keyboardHidden = KEYBOARDHIDDEN_UNDEFINED;
hardKeyboardHidden = HARDKEYBOARDHIDDEN_UNDEFINED;
navigation = NAVIGATION_UNDEFINED;
navigationHidden = NAVIGATIONHIDDEN_UNDEFINED;
orientation = ORIENTATION_UNDEFINED;
screenLayout = SCREENLAYOUT_UNDEFINED;
uiMode = UI_MODE_TYPE_UNDEFINED;
screenWidthDp = compatScreenWidthDp = SCREEN_WIDTH_DP_UNDEFINED;
screenHeightDp = compatScreenHeightDp = SCREEN_HEIGHT_DP_UNDEFINED;
smallestScreenWidthDp = compatSmallestScreenWidthDp = SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
densityDpi = DENSITY_DPI_UNDEFINED;
seq = 0;
}
因此扶叉,我們只需要把fontScale
屬性值設(shè)置成默認(rèn)值1即可。一開始我也沒考慮到這個點帕膜,感謝sollian在評論留言的提醒枣氧。
總結(jié)
- 若是想要全局控制字體是否受系統(tǒng)設(shè)置影響,推薦使用方法二重寫
getResources
方法泳叠。 - 若是部分字體不需要受系統(tǒng)設(shè)置影響作瞄,部分字體需要受系統(tǒng)設(shè)置影響茶宵,推薦使用方法一危纫。