框架源碼地址:?https://github.com/ximsfei/Android-skin-support
基本原理:
Android-skin-support 這個框架的主要思路是:
1. 更換LayoutInflaterFactory,對從xml布局文件要解析出來的 View,如果有相對應(yīng)的支持換膚功能的控件(即實(shí)現(xiàn)SkinCompatSupportable接口的控件),就創(chuàng)建支持換膚功能的控件,然后把這個控件保存起來,如果沒有就創(chuàng)建本來的控件(這個是不保存的);
2. 當(dāng)收到換膚通知的時候,就調(diào)用所有保存里來的控件的applySkin() 進(jìn)行換膚操作。
簡單使用:
1. 初始化:
2. 更換SDcard 上的皮膚:
3. 換回默認(rèn)皮膚:
接下來我們來看看源碼。
一、簡單的框架邏輯:
1. 在 Application 中注冊 SkinActivityLifecycle 監(jiān)聽Activity生命周期;
2. 在 SkinActivityLifecycle 中 onActivityCreated() 設(shè)置
3. getSkinDelegate()中創(chuàng)建SkinCompatDelegate實(shí)例和activity綁定起來存入WeakHashMapmSkinDelegateMap中;
4. 在 SkinCompatDelegate 的回調(diào) onCreateView()(和這個類的實(shí)例綁定的activity的所有view都會走這個函數(shù)) 判斷view是否支持換膚功能,如果支持就存入 List> mSkinHelpers:
View view = createView(parent, name, context, attrs); //創(chuàng)建實(shí)現(xiàn)了SkinCompatSupportable的view實(shí)例
5. 在 SkinActivityLifecycle 的 onActivityResumed() 中創(chuàng)建皮膚更換觀察者,并存入本實(shí)例的WeakHashMapmSkinObserverMap和 SkinCompatManager 的 ArrayListobservers:
創(chuàng)建皮膚觀察者:
6. 在 SkinActivityLifecycle 的 onActivityDestroyed() 中移除與該activity綁定SkinCompatDelegate實(shí)例、SkinObserver:
二、更換皮膚邏輯:
1. 調(diào)用SkinCompatManager.getInstance().loadSkin("night", null, SkinCompatManager.SKIN_LOADER_STRATEGY_BUILD_IN); 啟動一個異步任務(wù)SkinLoadTask:
2. 在異步任務(wù) SkinLoadTask 的 doInBackground() 中根據(jù)strategy調(diào)用不同的皮膚包加載策略類的loadSkinInBackground(), 比如放在Assets皮膚包,這邊就是從Assets復(fù)制皮膚包到getExternalCacheDir()目錄下的skins目錄下。
3. 在異步任務(wù) SkinLoadTask 的 onPostExecute() 調(diào)用 SkinCompatManager 的 notifyUpdateSkin() 通知所有的 SkinObserver 皮膚更新了。
4. 回調(diào) 在 SkinActivityLifecycle 創(chuàng)建的 SkinObserver 實(shí)例的 updateSkin():
5. 調(diào)用 acitvity 對應(yīng)的 SkinCompatDelegate 的 applySkin();
6. 在 SkinCompatDelegate 的 applySkin() 里面遍歷mSkinHelpers(該activity所有的View實(shí)例)的applySkin();
7. 在 View 實(shí)例的 applySkin() 里面實(shí)現(xiàn)了關(guān)于這個控件換皮膚的操作。
三、LayoutInflaterFactory 創(chuàng)建解析出來的view相對應(yīng)的支持換膚功能的控件
createViewFromHackInflater()? 這里創(chuàng)建我們通過addHookInflater() 添加對應(yīng)某個view替換成支持換膚的控件的規(guī)則,可以用來覆蓋框架自帶對應(yīng)的支持換膚的控件,即對應(yīng)某個view,創(chuàng)建我們的自己的控件,不創(chuàng)建框架自帶的控件。
createViewFromInflater() 和上面不同,框架默認(rèn)支持基本常用控件和一些V7包上的一些控件的替換,如果你需要添加其他控件的替換,可以使用addInflater()添加對應(yīng)規(guī)則的View,但是覆蓋不了框架默認(rèn)支持的基本常用控件和一些V7包上的一些控件的替換控件。
基本常用控件的替換:
V7 包只替換了 Toolbar :