通過設定字號,同步改變全域的字體,
長文干貨,建議點贊收藏,
實作方式有多種:
1.通過AppTheme主題設定
通過配置不同的字體主題,然后設定更換主題來改變全域的字體樣式,主題中可配置自定義字體大小等;xml布局中也需要添加style主題,設定主題后需要recreate ui,體驗不好,
2.修改系統fontScale,縮放字體大小
百度字體設定等,很多方案都是這種,主要重寫Application的onConfigurationChanged監聽系統字體大小變化,然后重啟app或者activity才會重繪同步,而且對數值不可控,還會影響一些默認配置以及存在適配問題,不作深入研究,直接拋棄,
3.自定義view
每個view中會有一個監聽,修改字體后觸發監聽更改字體;每次創建讀取本地快取,設定字體;需要在顯示的地方更換為自定義的view,
看著略顯麻煩,但是不得不說,很靈活,并且方便擴展需求,但是麻煩,除了自定義view還得處理監聽,
4.自定義binding屬性「最終選擇」
類似于方案3,在binding方法中去初始化跟設定字體,擴展性好,并且不需要替換textview,流程就跟方案1類似,需要在xml中配置型別屬性,然后binding會自動根據配置的屬性去設定字體,
全域字體設定之自定義binding
先看效果圖,在設定頁面,通過設定字體的型別,然后保存下來,同時重繪binding監聽,更改所有顯示的textview字體大小,
并且可以方便擴展,比如tablayout中選中放大等效果,

首先新建字體設定工具類,
用于存盤字體型別,獲取字體樣式,
class FontUtils { companion object { private const val TAG = "FontUtils" private const val KEY_APP_FONT = "key_app_font" //標準字體 const val NORMAL_FONT_STYLE = "normal_text_size" //大號字體 const val BIG_FONT_STYLE = "big_text_size" //特大字體 const val LARGE_FONT_STYLE = "large_text_size" private val instance by lazy { FontUtils() } fun getFontUtils(): FontUtils = instance } /** 字體樣式型別 */ fun getAppFontStyle(): String { return SPUtils.getInstance().getString(KEY_APP_FONT, NORMAL_FONT_STYLE) } fun saveAppFontStyle(appFontStyle: String?) { SPUtils.getInstance().put(KEY_APP_FONT, appFontStyle) } /** 獲取模型 */ fun getFontVo(fontType: String?): FontBean? { val fontStyle: String = getAppFontStyle() val fontVoList: List<FontBean>? = getRawFileList(fontStyle) return if (CollectionUtils.isNotEmpty(fontVoList)) { // LogUtils.i(TAG, "getFontVo-- fontVo:" + GsonUtils.toJson(fontVo)); getFontByType(fontVoList, fontType) } else null } /** * 決議模型 * @param fontType 具體字號型別 * */ private fun getFontByType(fontVoList: List<FontBean>?, fontType: String?): FontBean? { return CollectionUtils.find( fontVoList ) { it != null && StringUtils.equals(it.fontType, fontType) } } /** 字體模型 */ private fun getRawFileList(fontStyle: String?): List<FontBean>? { return when { StringUtils.equals(NORMAL_FONT_STYLE, fontStyle) -> { getFontListByRaw(R.raw.font_normal) } StringUtils.equals(BIG_FONT_STYLE, fontStyle) -> { getFontListByRaw(R.raw.font_big) } StringUtils.equals(LARGE_FONT_STYLE, fontStyle) -> { getFontListByRaw(R.raw.font_large) } else -> getFontListByRaw(R.raw.font_normal) } } /** 讀取本地模型 路徑 /res/raw/resId */ private fun getFontListByRaw(@RawRes resId: Int): List<FontBean>? { return GsonUtils.fromJson<List<FontBean>>( ResourceUtils.readRaw2String(resId), object : TypeToken<List<FontBean>>() {}.type ) } }View Code
下面是字體模型截圖,類似方案1中的字體主題,分別對應設定頁面的標準字體,大號字體,特大字體,可隨意擴展,
xml中設定的字體型別就來自模型中讀取的數值

接下來就是自定義binding屬性,具體設定方法,
@BindingAdapter(value = https://www.cnblogs.com/LiuZhen/archive/2021/08/27/["bindFontType"], requireAll = false) fun TextView.setBindingFontStyle(fontType: String?) { if (TextUtils.isEmpty(fontType)) { LogUtils.i("setBindingFontStyle", "IS NULL") return } //去除字體內邊距 includeFontPadding = false val fontVo: FontBean? = FontUtils.getFontUtils().getFontVo(fontType) if (fontVo != null) { textSize = fontVo.fontSize } val activity = ActivityUtils.getActivityByContext(context) as AppCompatActivity? if (activity != null) { LiveEventBus .get(LiveEventBusKey.FONT_STYLE, Int::class.java) .observe(activity, { val fontBean: FontBean? = FontUtils.getFontUtils().getFontVo(fontType) if (fontBean != null) { textSize = fontBean.fontSize } }) } }View Code
自定義binding方法中通過livedata注冊了一個監聽,所以跟方案3類似,實則是每一個textview都存在一個監聽,而livedata可以系結生命周期,自動創建跟銷毀監聽,避免記憶體泄漏,
在xml中系結設定的方法,

當布局創建時,會自動執行binding方法,
binding方法中會根據xml里的字體大小型別執行工具類中的getFontVo方法,
getFontVo方法回去讀取快取在本地的字體型別,等于主題型別,從而讀取到具體的模型資料,拿到資料設定更新,
而binding方法中的監聽,系結了當前的生命周期,所以當頁面銷毀或回收時會自動解除監聽,
只要xml中設定了自定義的binding屬性,就能同步修改更新,不影響原本的設定,如絲滑般柔順,
當然,因為是基于binding,所以專案得基于databinding才行,
因為我后面接觸過的專案都是databinding,并且也是主流,
如果不是就推薦方案3了,通過自定義view實作,大致流程也差不多,
碼字不易,喜歡就賞個贊吧,
自定義擴展
因為是binding,所以有時候在無法滿足需求的情況下可以額外擴展方法,
比如tablayout,實作一個選中字體放大的效果,
@BindingAdapter(value = https://www.cnblogs.com/LiuZhen/archive/2021/08/27/["bindFontType", "isCheck", "checkBuffSize"], requireAll = false) fun TextView.setBindingFontStyle(fontType: String?, isCheck: Boolean, checkBuffSize: Int) { if (TextUtils.isEmpty(fontType)) { LogUtils.i("setBindingFontStyle", "IS NULL") return } //去除字體內邊距 includeFontPadding = false //選中字體 val fontVo: FontBean? = FontUtils.getFontUtils().getFontVo(fontType) if (fontVo != null) { textSize = if (isCheck) { fontVo.fontSize + checkBuffSize } else { fontVo.fontSize } } val activity = ActivityUtils.getActivityByContext(context) as AppCompatActivity? if (activity != null) { LiveEventBus .get(LiveEventBusKey.FONT_STYLE, Int::class.java) .observe(activity, { val fontBean: FontBean? = FontUtils.getFontUtils().getFontVo(fontType) if (fontBean != null) { textSize = fontBean.fontSize } }) } }View Code
很簡單,擴展了兩個屬性,一個是否選中,一個是增量,
只需要在xml中動態配置一下,然后通過邏輯控制就能同步設定,

這里有時候會碰到一些問題,比如tablayout例子,
如果是自定義tablayout,customview并沒有參與系結,無法實作監聽的情況,
這里可以手動系結一下解決,引數可以統一設定在binding方法中,也可以額外設定,不過最好統一管理,便于擴展跟維護,
/** * 配置選中/未選中狀態 */ private fun setTabLayoutSelected(tab: TabLayout.Tab, isCheck: Boolean) { val topicBinding: TabviewTopicBinding? = DataBindingUtil.getBinding(tab.customView!!) if (topicBinding != null) { topicBinding.setIsCheck(isCheck)//通過binding統一控制 if (isCheck) {//也可以隨意 topicBinding.tvTitle.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD)) } else { topicBinding.tvTitle.setTypeface(Typeface.defaultFromStyle(Typeface.NORMAL)) } } }View Code
只要把工具類封裝好了,后續只需要設定binding屬性就行,
在需求跟擴展以及重繪效果來說,這個方案是很不錯的,
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/296451.html
標籤:其他
上一篇:MVP框架模式
