框架源碼地址:?https://github.com/ximsfei/Android-skin-support
基本原理:
Android-skin-support 這個(gè)框架的主要思路是:
1. 更換LayoutInflaterFactory刁赦,對(duì)從xml布局文件要解析出來的 View烦却,如果有相對(duì)應(yīng)的支持換膚功能的控件(即實(shí)現(xiàn)SkinCompatSupportable接口的控件),就創(chuàng)建支持換膚功能的控件胚嘲,然后把這個(gè)控件保存起來肉津,如果沒有就創(chuàng)建本來的控件(這個(gè)是不保存的)强胰;
2. 當(dāng)收到換膚通知的時(shí)候,就調(diào)用所有保存里來的控件的applySkin() 進(jìn)行換膚操作妹沙。
簡(jiǎn)單使用:
1. 初始化:
2. 更換SDcard 上的皮膚:
3. 換回默認(rèn)皮膚:
接下來我們來看看源碼偶洋。
一、簡(jiǎn)單的框架邏輯:
1. 在 Application 中注冊(cè) SkinActivityLifecycle 監(jiān)聽Activity生命周期距糖;
2. 在 SkinActivityLifecycle 中 onActivityCreated() 設(shè)置
3. getSkinDelegate()中創(chuàng)建SkinCompatDelegate實(shí)例和activity綁定起來存入WeakHashMapmSkinDelegateMap中玄窝;
4. 在 SkinCompatDelegate 的回調(diào) onCreateView()(和這個(gè)類的實(shí)例綁定的activity的所有view都會(huì)走這個(gè)函數(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); 啟動(dòng)一個(gè)異步任務(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 對(duì)應(yīng)的 SkinCompatDelegate 的 applySkin();
6. 在 SkinCompatDelegate 的 applySkin() 里面遍歷mSkinHelpers(該activity所有的View實(shí)例)的applySkin();
7. 在 View 實(shí)例的 applySkin() 里面實(shí)現(xiàn)了關(guān)于這個(gè)控件換皮膚的操作典阵。
三奋渔、LayoutInflaterFactory 創(chuàng)建解析出來的view相對(duì)應(yīng)的支持換膚功能的控件
createViewFromHackInflater()? 這里創(chuàng)建我們通過addHookInflater() 添加對(duì)應(yīng)某個(gè)view替換成支持換膚的控件的規(guī)則镊逝,可以用來覆蓋框架自帶對(duì)應(yīng)的支持換膚的控件壮啊,即對(duì)應(yīng)某個(gè)view,創(chuàng)建我們的自己的控件撑蒜,不創(chuàng)建框架自帶的控件歹啼。
createViewFromInflater() 和上面不同,框架默認(rèn)支持基本常用控件和一些V7包上的一些控件的替換座菠,如果你需要添加其他控件的替換狸眼,可以使用addInflater()添加對(duì)應(yīng)規(guī)則的View,但是覆蓋不了框架默認(rèn)支持的基本常用控件和一些V7包上的一些控件的替換控件浴滴。
基本常用控件的替換:
V7 包只替換了 Toolbar :