本文為原創,轉載請注明出處。
文章標題為夜間模式,其實我這里想說的不是什么夜間模式,而是Skin庫,有了Skin庫,分分鐘實現換膚那是小Case,并且也能分分鐘實現換膚功能。當然還是那句話,說的那么屌,沒圖談個幾把,所以還是上個圖說話:
簡單介紹下圖片內容:我在apk中內置了普通模式和夜間模式兩套值,并且外置皮膚中也內置了普通模式和夜間模式。
本文為發布在Github上Skin庫的Wiki,實現了Android開發中換膚的功能,歡迎各位Star。以下為Wiki內容:
說在前面的
Skin的快速使用這篇文章介紹了如何快速使用本庫達到換膚,基本滿足了日常的換膚需求。本篇文章著重介紹Skin庫的特點。
換膚要求
不管你是準備在新工程中還是在已有工程中使用換膚功能,唯一的要求都需要你對需要換膚的資源進行規范的管理,這個規范的管理指資源的命名/分類。命名指資源的名字具有一定的規范而不是隨意的命名,分類指你能夠清除的知道哪些資源你是需要用于換膚的。
不管你使用何種換膚方式即使不適用Skin,這個規范都是極其重要的,切記。
Skin詳細介紹
1. 屬性解析工廠SkinAttrFactory
屬性解析工廠描述了如何以什么規則去解析目標屬性,也就是什么屬性才認為是需要進行換膚的屬性。Skin提供了兩個屬性解析工廠的實現:前綴屬性解析和標記屬性解析。屬性解析工廠是整個Skin中的主要組件之一。目前屬性解析工廠支持解析style(eg: style="@style/xxx")和引用屬性(eg: android:background="@drawable/xxx",不支持值類型(eg: android:background="#ffffff")的屬性。
前綴屬性解析工廠PrefixSkinAttrFactory
PrefixSkinAttrFactory
解析屬性的規則是將包含有特定前綴的屬性解析出來,eg:skin_login_bg.jpg
。PrefixSkinAttrFactory
會依次解析布局文件中的每一個View的屬性。
- 前提:要求將工程中需要進行換膚的屬性都以固定的前綴開始命名,用戶可以設置任意的前綴,Skin默認以
skin
作為前綴。 - 優點:因為是以前綴為規則區別換膚的屬性,因此這種方式對已具規模的工程要實現換膚功能來說用處大的多,因為可以做到只修改資源名字而不用去修改引用資源的地方(比如布局文件)就可以實現資源的整理,修改資源名字的時候記得一并修改引用。
- 缺點:由于解析的時候會自動解析每一個布局文件中的元素,因此效率上不如接下來要講的標記屬性解析工廠。
標記屬性解析工廠NamespaceSkinAttrFactory
NamespaceSkinAttrFactory
解析屬性的規則是將布局文件中添加了http://schemas.android.com/android/skin
命名空間并且增加了標記的控件屬性解析出來。
eg:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
...
xmlns:skin="http://schemas.android.com/android/skin"
...>
<TextView
...
skin:enable="true"
...
/>
</FrameLayout>
- 前提:需要對進行換膚的控件增加標記。
- 優點:由于只會解析包含了標記的控件,因此解析效率上會更高,對新工程來說采用這種方式會更好。
- 缺點:由于需要打標記,因此對已具規模的工程帶來的勞力活會多一些。
可以擴展自己的屬性解析方式,只需繼承SkinAttrFactory即可。Skin默認配置標記屬性解析工廠,可以通過SkinManager改變配置。
相關Api
- 創建前綴屬性解析工廠:
SkinAttrFactory.createPrefixFactory(@Nullable String prefix)
- 創建標記屬性解析工廠:
SkinAttrFactory.createNamespaceFactory()
- 更改屬性解析配置:
SkinManager.setSkinAttrFactory(SkinAttrFactory factory)
2. 換膚屬性SkinAttr
SkinAttr
定義了Skin支持的屬性描述。Skin默認實現了background
,textColor
,src
三個屬性,通常這三個屬性已經滿足了大部分的控件屬性需求。
SkinAttrSupport
用于管理SkinAttr
,也就是說只有SkinAttrSupport
中注冊了的屬性才會被屬性解析工廠關注,而不會去處理其它額外的屬性,默認注冊了SkinAttr
的三個默認實現。
擴展自定義屬性支持
- 實現
SkinAttr
子類
實現SkinAttr.apply(View)
抽象方法,用于描述view如何使用屬性。 - 配置子類
調用SkinAttrSupport.addSupportAttr(String attrName, SkinAttr skinAttr)
方法即可添加自定義屬性。
同樣SkinAttrSupport.removeSupport(String attrName)
即可移除支持的屬性。
3. 換膚管理器SkinManager
SkinManager
為整個換膚庫的管理器,主要處理皮膚的加載,更新以及通知監聽者刷新等。SkinManager
需要在使用之前進行初始化,建議是在Application.onCreate()
方法中進行初始化。
相關Api:
-
public void init(Context context)
初始化 -
public boolean isUseSkin()
當前是否切換了皮膚 -
public void changeSkin(String suffix)
通過后綴切換皮膚。 -
public void loadSkin(String skinPath, final SkinLoadListener listener)
加載指定路徑的皮膚插件文件更換皮膚。 -
public void loadSkin(String skinPath, @Nullable final String suffix, final SkinLoadListener listener)
加載指定路徑的皮膚插件文件更換皮膚,并指定文件中的皮膚屬性后綴。 -
public void addSkinChangedListener(SkinChangedListener listener)
添加皮膚變化監聽 -
public void removeSkinChangedListener(SkinChangedListener listener)
移除皮膚變化監聽 -
public void notifySkinChangedListeners()
通知皮膚更新 -
public void setIgnoreWhenAttrNotFound(boolean ignore)
設置資源未找到時是否忽略設置,默認為true -
public void setSkinAttrFactory(SkinAttrFactory factory)
設置屬性解析工廠,默認使用標記屬性解析工廠。
4. 界面換膚委托SkinDelegate
SkinDelegate
包含了界面實現換膚所需要的處理。其主要功能是描述了控件的加載方式,以及界面中需要進行換膚的控件管理,以及相應的界面刷新等處理。
相關Api:
-
public void beforeCallSuperOnCreate()
在Activity
調用super.onCreate()
之前調用。用于設置界面的布局加載器LayoutInflaterFactory
-
public void afterCallSuperOnCreate()
在Activity
調用super.onCreate()
之后調用。用于切換狀態欄顏色等,建議使用我easy庫中的透明狀態欄實現。 -
public void onDestroy()
在Activity
的onDestroy()
方法中調用,用于移除界面刷新回調,以及資源回收等處理(暫無需要處理)。 -
public void setEnableSkinSwitchAnim(boolean mEnableSkinSwitchAnim)
是否允許控件切換主題時使用動畫(默認Fade in),默認開啟。 -
public void setIsSkinSwitchAnimAlways(boolean mIsSkinSwitchAnimAlways)
設置需要進行皮膚切換的view屬性沒有改變時是否也有動畫切換,默認為false
如果不想管理SkinDelegate,則可以使用BaseSkinActivity
作為程序中Activity的基類,其代管了SkinDelegate
的實現。
對于已具規模的工程,可能已經有自己的BaseActivity
,則可以仿照BaseSkinActivity
管理一個SkinDelegate
即可。