Android中App字體不隨系統字體大小的改變而改變
通常是在Application或Activity中複寫getResources方法 ,下面的代碼就實現了app字體不隨系統字體大小改變.
override fun getResources(): Resources {
val res = super.getResources()
if(res != null && res.configuration.fontScale != 1f){
val config = res.configuration
config.setToDefaults()
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 ){
createConfigurationContext(config)
}else
res.updateConfiguration(config, res.displayMetrics)
}
return super.getResources()
}
還可以將textView的單位設置爲dp,這樣也不會跟隨系統字體大小改變,但是這裏有個不好的地方,如果app中要求可以調節app全局的字體大小功能,這時候用dp作爲單位就不太好了.
一般上面重寫getResources函數,是在app啓動的時候纔會生效,假設app在運行的時候~用戶跑去系統設置裏更改字體大小,這時候上面的配置不就不會生效了,而app裏的文字會跟着系統設置的字體大小而改變. 怎麼解決呢? 重寫Application的onConfigurationChanged函數做監聽操作,當系統字體大小發生變化,會觸發這個函數的調用,所以可以在該函數內重啓應用或主Activity,使得上面的getResources會被調用,從而app裏的文字不就不會跟着系統設置的字體大小而改變
@Override
public void onConfigurationChanged(Configuration newConfig) {
if(newConfig.fontScale > 1){
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
}
super.onConfigurationChanged(newConfig);
}
遇到的問題:
-
在Android7.0中,調用Configuration類的setToDefaults函數,會使得Dialog彈框不顯示(半透明背景顯示),這是因爲在Android7.0中,Configuration類的setToDefaults函數內將screenWidthDp和screenHeightDp都置爲0 (SCREEN_WIDTH_DP_UNDEFINED和SCREEN_HEIGHT_DP_UNDEFINED的值都爲0), 從而造成dialog顯示不了,怎麼解決? 不調用setToDefaults函數,而單獨設置Configuration類的屬性,例如需要設置fontScale,代碼如下
override fun getResources(): Resources { val res = super.getResources() if(res != null && res.configuration.fontScale != 1f){ val config = res.configuration config.fontScale = 1f if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 ){ createConfigurationContext(config) }else res.updateConfiguration(config, res.displayMetrics) } return super.getResources() }
-
在Android7.x中,重寫getResources並不能使得app裏的文字不會跟着系統設置的字體大小而改變,需要重寫activity的attachBaseContext才能生效,代碼如下
override fun attachBaseContext(newBase: Context?) { if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N) { val res = newBase?.getResources() val config = res?.configuration config?.fontScale = 1 val newContext = newBase?.createConfigurationContext(config) super.attachBaseContext(newContext) return } super.attachBaseContext(newBase) }
app中要求可以調節app全局的字體大小功能實現
通過設置configuration類的fontScale來控制字體的縮放比例,從而實現app全局的字體大小控制. 建議一般標準字體按照 “1” 這個值來取,大字體可以設置爲1.3.
fun setFontScale(fontScale: Float) {
val res = resources
val configuration = res.configuration
configuration.fontScale = fontScale
res.updateConfiguration(configuration, res.displayMetrics)
}
注意:通過代碼取當前頁面textView,其字體大小值的單位是px,需要轉化爲sp,才能乘以上面的fontScale,從而拿到放大之後的字體大小值
Autosizing TextViews
當app文字大小需要根據系統文字大小,或app中設置fontScale值進行調整時,可能會導致TextView文字溢出,部分不能顯示的問題,因爲TextView是無法根據字體大小來動態控制寬高的,所以這時候Android8.0新增用來動態改變TextView字體大小的新特性 Autosizing TextViews 就上場了,Autosizing TextViews使得TextView可以動態調整其文字的大小,使得不會出現溢出或部分顯示這種問題.
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<TextView
android:layout_width="340dp"
android:layout_height="50dp"
android:background="@drawable/shape_bg_008577"
android:gravity="center_vertical"
android:maxLines="1"
android:text="Autosizing TextViews 用來動態改變TextView字體大小"
android:textSize="18sp"
android:autoSizeTextType="uniform"
android:autoSizeMaxTextSize="18sp"
android:autoSizeMinTextSize="10sp"
android:autoSizeStepGranularity="1sp"/>
</LinearLayout>
主要通過上面4個auto開頭的屬性來控制,具體屬性意義自行查閱官方文檔.當需要兼容8.0以下設備,則需要用AppCompatTextView代替TextView,並且上面幾個屬性的命名空間需要用app命名空間.
<android.support.v7.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="@dimen/dimen_size_30"
android:text="Autosizing TextViews 用來動態改變TextView字體大小"
app:autoSizeTextType="uniform"
app:autoSizeMaxTextSize="@dimen/textsize_16"
app:autoSizeMinTextSize="@dimen/textsize_12"
android:autoSizeStepGranularity="@dimen/textsize_2"/>
注意: 在AppCompatTextView使用android命名空間的auto開頭的屬性," 動態改變TextView字體大小 " 無效果