使用步驟
首先,請(qǐng)先確認(rèn)你希望以什么樣的形式封裝你的主題對(duì)象,以 QMUI Demo 為例,每個(gè)主題對(duì)應(yīng)一個(gè)配置表,每個(gè)配置表均為一個(gè) NSObject<QDThemeProtocol> * 類(lèi)型。
然后,在盡量早的時(shí)機(jī)初始化 QMUIThemeManager,以保證其他使用顏色、圖片的地方能獲取到正確的值。
QMUI Demo 中選擇的時(shí)機(jī)是:application:didFinishLaunchingWithOptions:。
- 先注冊(cè)主題監(jiān)聽(tīng),在回調(diào)里將主題持久化存儲(chǔ)(存到數(shù)據(jù)庫(kù)或者 NSUserDefaults),避免啟動(dòng)過(guò)程中主題發(fā)生變化時(shí)讀取到錯(cuò)誤的值
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(handleThemeDidChangeNotification:)
name:QMUIThemeDidChangeNotification
object:nil];
- 然后設(shè)置用于生成主題的 block,在需要的時(shí)候 QMUIThemeManager 會(huì)通過(guò)這個(gè) block 得到一個(gè)主題對(duì)象
QMUIThemeManager.sharedInstance.themeGenerator = ^__kindof NSObject * _Nonnull(NSString * _Nonnull identifier) {
if ([identifier isEqualToString:@"Default"]) return QMUIConfigurationTemplate.new;
if ([identifier isEqualToString:@"Dark"]) return QMUIConfigurationTemplateDark.new;
return nil;
};
- 再針對(duì) iOS 13 開(kāi)啟自動(dòng)響應(yīng)系統(tǒng)的 Dark Mode 切換// 如果不需要兼容 iOS 13 Dark Mode,則不需要這一段代碼
if (@available(iOS 13.0, *)) {
// 先通過(guò)這個(gè) block 來(lái)決定當(dāng)系統(tǒng)的 Dark Mode 發(fā)生切換時(shí),要如何映射到業(yè)務(wù)的主題
QMUIThemeManager.sharedInstance.identifierForTrait = ^__kindof NSObject<NSCopying> * _Nonnull(UITraitCollection * _Nonnull trait) {
if (trait.userInterfaceStyle == UIUserInterfaceStyleDark) {
return @"Dark";// 表示當(dāng)檢測(cè)到系統(tǒng)開(kāi)啟了 Dark Mode 時(shí),將主題自動(dòng)切換到 Dark
}
return @"Default";
};
// 然后讓 QMUIThemeManager 自動(dòng)響應(yīng)系統(tǒng)的 Dark Mode 切換
QMUIThemeManager.sharedInstance.respondsSystemStyleAutomatically = YES;
}
做完以上的初始化配置后,剩下的就是業(yè)務(wù)界面的適配了,按照上文提到的,將 color、image、effect 都換成對(duì)應(yīng)的動(dòng)態(tài)對(duì)象。
view.backgroundColor = [UIColor qmui_colorWithThemeProvider:^UIColor * _Nonnull(__kindof QMUIThemeManager * _Nonnull manager, NSString * _Nullable identifier, __kindof NSObject * _Nullable theme) { return [identifier isEqualToString:@"Dark"] ? UIColor.blackColor : UIColor.whiteColor;}];
layer.backgroundColor = [UIColor qmui_colorWithThemeProvider:^UIColor * _Nonnull(__kindof QMUIThemeManager * _Nonnull manager, NSString * _Nullable identifier, __kindof NSObject * _Nullable theme) { return [identifier isEqualToString:@"Dark"] ? UIColor.blackColor : UIColor.whiteColor;}].CGColor;
imageView.image = [UIImage qmui_imageWithThemeProvider:^UIImage * _Nonnull(__kindof QMUIThemeManager * _Nonnull manager, NSString * _Nullable identifier, NSObject<QDThemeProtocol> *theme) { return [UIImage imageNamed:[identifier isEqualToString:@"Dark"] ? @"image_dark" : @"image_default"];}];
visualEffectView.effect = [UIVisualEffect qmui_effectWithThemeProvider:^UIVisualEffect * _Nonnull(__kindof QMUIThemeManager * _Nonnull manager, NSString * _Nullable identifier, NSObject<QDThemeProtocol> *theme) { return [UIBlurEffect effectWithStyle:[identifier isEqualToString:@"Dark"] ? UIBlurEffectStyleDark : UIBlurEffectStyleLight];}];
通常來(lái)說(shuō),一個(gè)項(xiàng)目里的顏色、模糊效果一般都只有可枚舉的固定的幾個(gè),建議將這些顏色、模糊效果緩存起來(lái)(使用 static 變量,或者用一個(gè)單例去保存,可參考 QDThemeManager),這樣可以大大減少代碼量,也不需要去記住創(chuàng)建動(dòng)態(tài)對(duì)象的語(yǔ)法。
// 適當(dāng)做一些抽取,就可以減少大量的代碼
view.backgroundColor = UIColor.qd_backgroundColor;
layer.backgroundColor = UIColor.qd_separatorColor.CGColor;
visualEffectView.effect = UIVisualEffect.qd_standardBlurEffect;
到此大部分界面已經(jīng)可以兼容,而對(duì)于自定義的 View 組件,它們的自定義屬性需要在主題切換時(shí)被刷新,則可參照下方來(lái)注冊(cè)屬性給 QMUIThemeManager。
@implementation CustomView
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
// ...
// 將組件里的樣式定義為 property,然后通過(guò) qmui_registerThemeColorProperties: 注冊(cè)給 QMUIThemeManager,這樣當(dāng)主題發(fā)生變化時(shí),會(huì)遍歷整個(gè)界面的所有 view,重新設(shè)置被注冊(cè)的屬性
[self qmui_registerThemeColorProperties:@[NSStringFromSelector(@selector(borderColor)),
NSStringFromSelector(@selector(contentImage)),
NSStringFromSelector(@selector(backgroundEffect))]];
}
return self;
}
@end
如果上述提供的功能仍未能滿(mǎn)足業(yè)務(wù)的需求,也可直接重寫(xiě)
UIView/UIViewController 的 qmui_themeDidChangeByManager:identifier:theme: 方法,在內(nèi)部寫(xiě)自己的邏輯。
至此整個(gè) App 的主題實(shí)現(xiàn)和 Dark Mode 兼容工作就全部完成了。
至于主題的切換,如果 App 只是兼容 iOS 13 Dark Mode,則不需要理會(huì)這一點(diǎn),如果 App 里有提供主動(dòng)切換主題的操作給用戶(hù),則可參照以下代碼:
QMUIThemeManager.sharedInstance.currentThemeIdentifier = @"Dark";
// 切換到名為 Dark 的主題// 或
QMUIThemeManager.sharedInstance.currentTheme = darkTheme;
// 切換到 darkTheme 主題對(duì)象