
前言
目前市場上很多 App 都有主題變更、皮膚切換的功能。隨著項目代碼量的不斷增長,業(yè)務不斷完善,功能性代碼逐漸趨于模塊化,尤其是在多人協(xié)作開發(fā)同一個項目時,模塊解耦尤為重要,同時,公共基礎庫的功能性代碼使用越簡單越好。
前段時間在維護舊項目時,收到 App 主題變更、皮膚切換的需求,其包括 App 中各種圖標、色值、文字、字體等都包括在內,都需實現(xiàn)主題化。主要用于:
- 活動主題展示:比較典型的是類似京東618、天貓?zhí)詫氋徫锕?jié)主題變更。
- 用戶夜間模式:類似閱讀相關 App 的夜間模式,如:簡書等。
- 用戶主題變更:用戶可通過本地或者遠程下載喜歡的主題,如:網(wǎng)易云音樂、QQ 音樂等 App 主題變更。
由于老項目代碼比較混亂,功能模塊耦合嚴重以及開發(fā)時間等綜合因素,在實現(xiàn) App 主題變更、皮膚切換的功能的同時,想要在盡量不修改舊代碼的基礎上增加新的功能是比較麻煩的。
由于沒有合適的第三方庫,于是自己手擼了一個庫 SakuraKit,并開源,希望能幫到需要的朋友。
下面我們開始介紹 SakuraKit 及快速入門。
SakuraKit
SakuraKit,是一個輕量級的、專門用于 App 主題變更、皮膚切換的開源庫(靈感源自 SwiftTheme、DKNightVersion等),采用函數(shù)式 + 鏈式的編碼方式,簡單實用、方便理解、利于維護。
快速入門
效果
在體驗前,我們先來看看效果圖:

體驗
下面以 UIButton 為例,介紹如何使用 SakuraKit 進行主題化:
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
button.sakura
.backgroundColor(@"Home.buttonBackgroundColor")
.titleColor(@"Home.buttonTitleColor", UIControlStateNormal);
上述代碼是給一個 button 的背景色(backgroundColor)以及標題顏色(titleColor)進行主題化。其中 Home.buttonBackgroundColor 與 Home.buttonTitleColor 屬配置文件中的 KeyPath,配置文件的功能有點類似語言本地化文件(Localizable.strings)。后文會重點介紹如何設置配置文件。
到此為止,我們已經(jīng)實現(xiàn)了 button 按鈕主題化功能,如果你想切換主題,可以調用如下 API:
+ (BOOL)shiftSakuraWithName:(TXSakuraName *)name type:(TXSakuraType)type;
其中 name 參數(shù)代表主題的名稱,type 參數(shù)代表主題類型(目前有兩種:沙盒和本地)。
現(xiàn)在我們再具體的介紹一下如何使用 SakuraKit。
配置文件
做過 App 語言本地化的童鞋,應該比較熟悉 Localizable.strings 文件配置,同理,我們在使用 SakuraKit 對 App 進行主題化時,也需要進行類似的配置。目前支持 .json 和 .plist 兩種文件格式。
下面我們以 .json 文件格式做示例:
{
"Home":{
"buttonBackgroundColor":"#BB503D",
"buttonTitleColor":"#4AF2A1"
}
}
在上述體驗代碼中,我們看到這樣的字符串:Home.buttonBackgroundColor 和 Home.buttonTitleColor,這其實就是配置文件中字典的 KeyPath,通過 KeyPath 可以取得不同主題下的值,如:色值、圖片名稱、文字、字體大小等等。
注意事項:
- 每個主題都有自己配置文件,包括本地和沙盒主題。(本地主題名叫 default)。
- 主題名稱與配置文件名稱一致,如:某個主題名叫 fish,那么該主題相應的配置文件就應命名為fish.json。(建議遵守該約定)
- 不同本地主題的切圖命名要做區(qū)分,不同遠程主題的切圖命名應一致。
本地主題
本地主題,即用戶無需下載的主題,在 App Bundle 中。除了 App 本身自帶的默認主題外,SakuraKit 還能夠為 App 新增多種本地主題。
配置步驟如下:
步驟一
新建 .json 配置文件,比如新建一個名叫 typewriter 的主題,因此配置文件命名為 typewriter.json。
步驟二
配置一套切圖,并且命名與已有的主題要做區(qū)分。
步驟三
完成上述步驟后,在 AppDelegate 中 -application:application didFinishLaunchingWithOptions:launchOptions API 注冊所有本地主題:
// 注意:本地默認主題無需注冊
[TXSakuraManager registerLocalSakuraWithNames:@[@"typewriter"]];
步驟四
調用切換主題 API 即可切換至該指定主題:
[TXSakuraManager shiftSakuraWithName:@"typewriter" type:TXSakuraTypeMainBundle];
遠程主題
遠程主題(資源壓縮包.zip),即用戶通過網(wǎng)絡下載的主題,后臺可動態(tài)配置。同本地主題一致,分為兩部分:配置文件 + 切圖。當配置文件和切圖都弄好后,將文件夾打包成zip文件,傳給后臺即可。主題數(shù)據(jù)格式如下(僅供參考):
{
"name": "嘻多猴",
"sakuraName": "monkey",
"url": "http:\\image.tingxins.cn\sakura\monkey.zip"
}
sakuraName 是切換主題時用的名稱,而 url 是該主題的下載地址。(注:如果 sakuraName 字段傳空,那么主題的名稱將默認為下載的壓縮包名稱)
當遠程主題下載完畢后,可以這樣切換主題:
[TXSakuraManager shiftSakuraWithName:sakuraName type:TXSakuraTypeSandBox];
值得一提的是,SakuraKit 提供了一些主題下載的簡單接口,支持多種主題同時下載等操作,并且支持 Block 和 Delegate 兩種方式的回調,同時用戶還可自定義下載操作。
下面我們來依次介紹一下主題下載。
Block 方式
我們直接來介紹 API :
[[TXSakuraManager manager] tx_sakuraDownloadWithInfos:sakuraModel downloadProgressHandler:^(int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite) {
// 下載進度回調
} downloadErrorHandler:^(NSError * _Nullable error) {
// 下載過程出現(xiàn)錯誤回調
} unzipProgressHandler:^(unsigned long long loaded, unsigned long long total) {
// 主題下載完成后,解壓進度回調
} completedHandler:^(id<TXSakuraDownloadProtocol> _Nullable infos, NSURL * _Nullable location) {
// 主題包解壓完畢回調
} ];
其中 sakuraModel 模型數(shù)據(jù)遵守了 TXSakuraDownloadProtocol 協(xié)議,具體使用詳見 SakuraDemo_OC,在 DownloadSakuraController 控制器演示了該操作。
Delegate 方式
步驟一
直接調用 API 實現(xiàn)主題下載:
[[TXSakuraManager manager] tx_sakuraDownloadWithInfos:sakuraModel delegate:self];
步驟二
如果針對步驟一的下載操作需要回調,那么可以選擇性的再實現(xiàn)以下方法:
// 重復點擊下載某一主題,如果該主題已經(jīng)處于下載中或者本地存在時將會回調,其中 status 標識該 downloadTask 狀態(tài)。
- (void)sakuraManagerDownload:(TXSakuraManager *)manager
downloadTask:(NSURLSessionDownloadTask *)downloadTask
status:(TXSakuraDownloadTaskStatus)status;
// 主題下載完畢時回調,其中 infos 包括主題名稱,可通過該參數(shù)直接切換至該主題
- (void)sakuraManagerDownload:(TXSakuraManager *)manager
downloadTask:(NSURLSessionDownloadTask *)downloadTask
sakuraInfos:(id<TXSakuraDownloadProtocol>)infos
didFinishDownloadingToURL:(NSURL *)location;
// 主題下載進度
- (void)sakuraManagerDownload:(TXSakuraManager *)manager
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite;
/** Reserved for future use */
- (void)sakuraManagerDownload:(TXSakuraManager *)manager
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes;
// 下載操作出現(xiàn)錯誤時回調
- (void)sakuraManagerDownload:(TXSakuraManager *)manager
sessionTask:(NSURLSessionTask *)downloadTask
didCompleteWithError:(nullable NSError *)error;
// 主題下載包解壓進度回調
- (void)sakuraManagerDownload:(TXSakuraManager *)manager
downloadTask:(NSURLSessionDownloadTask *)downloadTask
progressEvent:(unsigned long long)loaded
total:(unsigned long long)total;
具體使用詳見 SakuraDemo_OC,在 AppDelegate 中演示了該操作。
自定義下載操作
除了上述自帶的下載操作外,SakuraKit 還提供了自定義下載操作相關的 API :
// sakuraModel 模型數(shù)據(jù)遵守了 TXSakuraDownloadProtocol 協(xié)議,location 即自定義下載下來的主題包地址。
[[TXSakuraManager manager] tx_generatePathWithInfos:sakuraModel downloadFileLocalURL:location successHandler:^(NSString *toFilePath, NSString *sakuraPath, TXSakuraName *sakuraName) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
BOOL isSuccess = [SSZipArchive unzipFileAtPath:toFilePath toDestination:sakuraPath delegate:self];
// 注意:自定義下載操作,必須進行 Sakura 路徑格式化!Required!
[TXSakuraManager formatSakuraPath:sakuraPath cleanCachePath:toFilePath];
dispatch_sync(dispatch_get_main_queue(), ^{
if (isSuccess) {
[TXSakuraManager shiftSakuraWithName:sakuraName type:TXSakuraTypeSandBox];
}
});
});
} errorHandler:^(NSError * _Nullable error) {
NSLog(@"errorDescription:%@",error);
}];
FQA
1.為何每個主題都有自己配置文件?
答:由于每個主題,除了切圖的命名是是一致的外,不同的主題背景色、字體大小可能不一樣,因此,每個主題都要有自己的配置文件,除非只對切圖進行本地化。
2.為何主題名稱與配置文件名稱一致?
答:這只是一個約定,SakuraKit 會通過主題名稱找到該主題在本地或者在沙盒中的路徑,使得主題名稱與配置文件名稱一致,可以減少不必要的工作量。
3.本地與沙盒主題有什么區(qū)別?
答:在本地主題稱為 mainBundle 主題,遠程主題稱為 Sandbox 主題。
開源
關于 SakuraKit 具體使用,詳見 Demo。
GitHub 項目地址:https://github.com/tingxins/SakuraKit
有什么問題或者更好的建議,GitHub 上直接提 issue 或者 PR。感謝支持
Demo 素材來源:網(wǎng)易云音樂等第三方 App,如有不妥之處,請及時聯(lián)系并予以刪除,謝謝。