一、前言
一個App發(fā)展到后期,沒有幾套主題,完全拿不出手啊。特別是toB的公 司,客戶要求自己的個性更是正常不過的需求了。換膚是個細活、細活、細活,重要的事說三遍,方案設(shè)計也是相當關(guān)鍵。
二、方案對比
2.1 換膚要處理的問題
1.配置抽離。
2.已存在界面的動態(tài)變換。
2.2 分析
針對第一點,確實沒太多說道,主要是和UI撕抽取公共配置和細節(jié)配置,這是一個細活。而界面的動態(tài)變換,這是一個麻煩事。
2.2.1 通知切換主題
這個事我們首先想到的就是通知,但是用通知太麻煩了,監(jiān)聽移除一個改變寫兩地。而且一個大型app,很多view其實并沒有屬性引用,使用通知又需要把這些view屬性引用出來,無形中增加了很多工作量。既然已經(jīng)有通知保底了,我們何不嘗試一下其它方案。
2.2.2 RX OR RAC
針對上面所說關(guān)于通知的兩個問題,我們使用 ReactiveCocoa 或 RXSwift 來優(yōu)雅的處理這個問題。不過大部分項目并沒有使用鏈式編程,為了換膚導入貌似不太劃算。
2.2.3 使用block來處理
在項目中建一個單例來管理配置,將所有顏色配置代碼塊放入block中并加入到單例的數(shù)組中管理,在切換主題時,遍歷數(shù)組執(zhí)行一遍block即可。當然使用時要注意block引用問題,保證視圖的正常釋放,隨著app的使用block會越來越多,要及時清理已釋放view的block。
三、block方案的實現(xiàn)
寫了個小Demo具體可看 github -ArtChangeTheme 下面做一些簡單的講解。
3.1 配置的模塊劃分
換膚是個細活,項目過大就需要進行模塊劃分,每個人負責自己的模塊,看似麻煩的事分到個人也就不多了。Demo寫了 Module1到Module4 四個模塊,每個模塊下都建了一個UIStyle文件夾用于管理當前模塊的配置。公共UIStyle則和模塊目錄同級。通過分類擴展。
- (NSString *)getStyleName_Module1;
每個模塊都要寫該方法,用于返回本模塊使用的配置文件plist。
方法的命名規(guī)則是 getStyleName_模塊名。 以此解耦,解耦思路是參考
測試用例執(zhí)行所有 以test開頭的方法,為此寫了個分類NSObject+ArtPrefix。
3.2 配置的解析
如上圖模塊下配置分為 Image 與 Style,Image為圖片配置,
3.2.1 圖片的配置
toPath表示圖片所在的相對文件夾,imageConfigs里面包含了需要動態(tài)配置的文件名以及備注,這是一個規(guī)范,我們可以很清楚的看到處理了哪些圖片,如果打包動態(tài)替換主題,也可通過該配置去替換需要的圖片。
3.2.2 Style樣式配置
color:000000,0.5 前面表示 Hex設(shè)置 0.5表示透明度。
font: 表示字體大小。
還有 ArtLayoutInfo 類對應(yīng)的屬性 是用于描述約束關(guān)系配置的,比如某些客戶可能對 banner 的寬高比有所要求,這個可以在這做擴展配置。
3.3 block方案接口設(shè)計
- (void)saveStrongSelf:(id)strongSelf block:(void(^)(id weakSelf))aBlock;
如上:考慮代碼的調(diào)用方便,和block及時的清理標記,設(shè)計了如上的調(diào)用接口,這樣大家不用寫__weak typeof(self) weakSelf = self,這么麻煩,但是如果block內(nèi)有用非weakSelf. 調(diào)用的view請注意弱引用聲明。
ArtUIStyleManager內(nèi)部開啟了定時器(默認60s可設(shè)置clearInterval控制間隔)去檢測清理無用的block。實現(xiàn)原理是將 strongSelf 弱引用存儲,檢測其被釋放后刪除對應(yīng)的block。至于弱引用存儲的實現(xiàn)大家可以看看 iOS - 如何實現(xiàn)弱引用字典,我這里使用的是block封裝與解封。這種小技巧平時用不到,關(guān)鍵時刻還是能幫你一把的。
- (void)reloadStylePath:(NSString *)aStylePath;
- (void)reloadStyleBundleName:(NSString *)aStyleBundleName;
- (void)reloadStyleBundle:(NSBundle *)aStyleBundle;
這三個方法是用于加載其它樣式的,具體可看demo中ArtModule4ViewController。
四、幾個小技巧
4.1 能用Color解決的就別麻煩UI出新圖了
很多UI控件都有個 tintColor 屬性,很多圖片是純色的,大家直接通過tintColor渲染就好了。Demo也提供了一個分類UIImage+ArtDraw來進行渲染繪制。不過我遇到了一個坑,我把渲染的圖做了拉伸,點擊了返回時,顏色還原成圖片本身的顏色。大家使用時注意一下即可。
4.2 iOS 8后系統(tǒng)自動會將@3x圖片自動適配圖片
如題,大家搜一下即可,也就是說來張@3x即可,要適配iOS8 一下的話,自己用代碼切一下也是沒問題的。不過雖說系統(tǒng)自動適配,但是我在1x的老iPad上出現(xiàn)了圖片虛化有毛邊的情況,加了1x圖就好很多,這個大家自己看著辦。
4.3 為什么不用iconfont呢
在iOS開發(fā)中使用iconfont圖標
為什么不用呢?唉,長嘆一聲。
五、來個HotReloader
換膚這個事,最蛋疼的應(yīng)該是,改一點跑一次代碼,這個耗時太久了,加一個小插件ArtUIStyleHotReloader 修改之后,command+s ,就能動態(tài)變了,當然只能模擬器使用。代碼很簡單,感謝VKCssProtocol。
六、結(jié)尾
2017.08.28,今天是個好日子,但是出了點事,心情不太好,這篇文章也就簡單的寫寫了。這個OC在原有的一些上面擴展的ArtUIStyle看著可能有些臃腫。改天抽空寫個swift版的,還是這個 github -ArtChangeTheme。趕緊去github給個小星星吧。
換膚這個事,UI自己要有套設(shè)計規(guī)范,如果前期沒有規(guī)范不要緊,做個換膚看他還有沒規(guī)范,再沒規(guī)范大家就GG了。最后來個擴展閱讀 VKCssProtocol。