使用DKNightVersion實(shí)現(xiàn)夜間模式

概述

DKNightVersion是github上面一個(gè)用于實(shí)現(xiàn)iOS應(yīng)用夜間模式和多種主題的開源庫角溃。github上面有兩個(gè)star數(shù)較高的庫,DKNightVersion和SwiftTheme。后者源碼是用swift實(shí)現(xiàn)的,OC和Swift混編導(dǎo)致應(yīng)用的體積大幅度增加,于是選擇了DKNightVersion喉誊。

使用方法

舉例說明,此處假設(shè)我們的Theme只有兩種:模式铺呵,夜間模式裹驰。

DKColorPicker Examples
view.dk_backgroundColorPicker = DKColorPickerWithColors([UIColor whiteColor], [UIColor darkGrayColor]); // => view的backgroundColor在日間模式隧熙、夜間模式下分別為white片挂、darkGray。
label.dk_textColorPicker = DKColorPickerWithColors([UIColor whiteColor], [UIColor darkGrayColor]);      // => label的textColor在日間模式贞盯、夜間模式下分別為white音念、darkGray。
tabBar.dk_barTintColorPicker = DKColorPickerWithColors([UIColor whiteColor], [UIColor darkGrayColor]);  // => tabBar的barTintColor在日間模式躏敢、夜間模式下分別為white闷愤、darkGray。

等等件余,能用別的方式來創(chuàng)建dk_XXXColorPicker嗎讥脐,比如RGB數(shù)值?當(dāng)然可以DKNightVersion提供了 DKColorPickerWithRGB(NSUInteger normal, ...)接口來根據(jù)色號生成dk_XXXColorPicker啼器。以上我們的Theme有n種旬渠,那么我們就需要在在dk_XXXColorPicker里面?zhèn)魅雗個(gè)代表顏色的參數(shù)。
也可以設(shè)置不同Theme下的圖片端壳。

DKImagePicker Examples
imageView.dk_image = DKImagePickerWithImages([UIImage imageNamed:@"white"], [UIImage imageNamed:@"black"]); // => imageView的image在日間模式告丢、夜間模式分別為圖片名為white、black代表的圖片损谦。

也有很多方法來生成dk_image,例如:DKImagePickersWithImageNames(@"white",@"black")岖免,直接根據(jù)圖片名來生成dk_image,等等照捡。

設(shè)置好了不同Theme下的顏色和圖片颅湘,如下代碼即可:

Theme Switch
[DKNightVersionManager sharedManager].themeVersion = DKThemeVersionNormal;// or DKThemeVersionNight => 將當(dāng)前的主題切換到日間模式或夜間模式。

實(shí)現(xiàn)思路

先看下上面的例子中用到的一些屬性栗精。

UIView+night
// DKColorPicker definition
@property (nonatomic, copy, setter = dk_setBackgroundColorPicker:) DKColorPicker dk_backgroundColorPicker;
// DKImagePicker definition
@property (nonatomic, copy, setter = dk_setTintColorPicker:) DKColorPicker dk_tintColorPicker;
UIImageView+night
@property (nullable, nonatomic, copy, setter = dk_setImagePicker:) DKImagePicker dk_imagePicker;

從使用方法里面可以看到我們在設(shè)置給UI控件的DKColorPicker屬性賦值時(shí)闯参,傳入了n個(gè)顏色。n個(gè)顏色對應(yīng)了n中Theme,而且他們根據(jù)索引一一對應(yīng)赢赊。

DKNightVersionManager是一個(gè)用于管理主題的單例乙漓。當(dāng)[DKNightVersionManager sharedManager].themeVersion 發(fā)生改變時(shí),也就是當(dāng)前的Theme發(fā)生了個(gè)改變释移。會發(fā)一個(gè)通知告訴所有的設(shè)置過DKColorPicker的UI控件叭披。
UI控件收到通知后去找DKNightVersionManager去拿到當(dāng)前的Theme,根據(jù)Theme更新UI控件的相關(guān)屬性(backgroundColor玩讳,tintColor, textColor, image等)涩蜘,這邊是實(shí)現(xiàn)這個(gè)功能一個(gè)大體的思路。

DKColorPicker是什么熏纯?它并不是一個(gè)用來存color的數(shù)組同诫,它的定義是這樣的:

DKColorPicker,DKImagePicker
typedef UIColor *(^DKColorPicker)(DKThemeVersion *themeVersion); 
typedef UIImage *(^DKImagePicker)(DKThemeVersion *themeVersion);

它是一個(gè)block樟澜,傳入一個(gè)我們已經(jīng)定義好了的Theme误窖,這個(gè)block給出一個(gè)color,用以更新秩贰。DKImagePicker同理霹俺。
每個(gè)對象都有一個(gè)pickers屬性

pickers property
@interface NSObject ()
@property (nonatomic, strong) NSMutableDictionary<NSString *, DKColorPicker> *pickers;
@end

在第一次使用這個(gè)屬性時(shí),當(dāng)前對象注冊為 DKNightVersionThemeChangingNotification 通知的觀察者毒费。pickers屬性只有在對象的某個(gè)DKColorPicker/DKImagePicker首次被賦值時(shí)才會被創(chuàng)建丙唧。

dk_backgroundColorPicker setter
- (void)dk_setBackgroundColorPicker:(DKColorPicker)picker {
    objc_setAssociatedObject(self, @selector(dk_backgroundColorPicker), picker, OBJC_ASSOCIATION_COPY_NONATOMIC);
    self.backgroundColor = picker(self.dk_manager.themeVersion);
    [self.pickers setValue:[picker copy] forKey:@"setBackgroundColor:"];
}

當(dāng)Theme發(fā)生變化時(shí),DKNightVersionManager會發(fā)出通知觅玻,所有監(jiān)聽DKNightVersionThemeChangingNotification的對象調(diào)用night_update方法去更新色值和圖片想际。實(shí)現(xiàn)如下:

notification action
- (void)night_updateColor {
    [self.pickers enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull selector, DKColorPicker  _Nonnull picker, BOOL * _Nonnull stop) {
        SEL sel = NSSelectorFromString(selector);
        // picker根據(jù)Theme拿到color/image值
        id result = picker(self.dk_manager.themeVersion);
        [UIView animateWithDuration:DKNightVersionAnimationDuration
                         animations:^{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
                             [self performSelector:sel withObject:result];
#pragma clang diagnostic pop
                         }];
    }];
}

從dk_backgroundColor的setter方法中可以知道,上面的selector一般為setBackgroundColor:溪厘,setTintColor;胡本,setImage:,根據(jù)selector生成方法桩匪,然后去更新對象的顏色打瘪,圖片等。這個(gè)庫已經(jīng)包含了所有的原生UI控件的color和image屬性傻昙,通過runtime,category給UI控件添加屬性闺骚。

作者推薦我們使用如下的方式來創(chuàng)建DKColorPicker。在DKColorTable.txt中妆档,配置我們需要的色值和主題僻爽,內(nèi)容如下:

NORMAL   NIGHT    RED
#ffffff  #343434  #fafafa BG
#aaaaaa  #313131  #aaaaaa SEP
#0000ff  #ffffff  #fa0000 TINT
#000000  #ffffff  #000000 TEXT
#ffffff  #444444  #ffffff BAR
#f0f0f0  #222222  #dedede HIGHLIGHTED

NORMAL 、NIGHT贾惦、RED分別對應(yīng)三個(gè)主題胸梆。
那么通過 DKColorPickerWithKey(BG)敦捧,生成對應(yīng)三個(gè)主題的DKColoPicker,并且目前的Theme只能通過修改DKColorTable.txt的文件內(nèi)容進(jìn)行管理碰镜。

總結(jié)

  • 這個(gè)庫可以實(shí)現(xiàn)我們當(dāng)前的大多數(shù)的需求兢卵,目前這個(gè)庫還不能比較方便的解決富文本的不同主題的不同樣式問題,我們可以參照它的實(shí)現(xiàn)給需要使用富文本的控件添加DKNightVersionThemeChangingNotification監(jiān)聽绪颖,從而根據(jù)不同的Theme做出不同的展現(xiàn)秽荤,這個(gè)思路當(dāng)然也可以拓展到其他地方,雖然會造成比較強(qiáng)的耦合關(guān)系柠横,如不同主題下的不同樣式的展現(xiàn)等等窃款。
  • 鑒于當(dāng)前Theme的管理方式,而且DKColorPicker用DKColorPickerWithKey()以外的其他方法創(chuàng)建傳入的數(shù)值并非動態(tài)的牍氛,所以以后增加Theme時(shí)可能會比較棘手晨继。作者不推薦我們手動創(chuàng)建DKColorPicker,而推薦使用DKColorTable.txt 來進(jìn)行主題管理, 這樣DKColorPicker中包含的色值由DKColorTable.txt中的配置決定搬俊,這樣會更加方便紊扬。
  • 它不僅僅支持原生的backgroundColor,tintColor等屬性悠抹,可以給自定義的控件添加一個(gè)你想要的的color/image屬性珠月,例如pressedColor,在不同的主題做出不同的展現(xiàn)楔敌。
  • 這個(gè)庫的一個(gè)比較好的實(shí)現(xiàn)我覺得是把Block當(dāng)做一個(gè)屬性賦值給對象而不是存儲一個(gè)數(shù)組或字典,然后根據(jù)其他變量的變化做出響應(yīng)的一個(gè)思路驻谆。
  • 使用的時(shí)候我們自己新建一個(gè)theme_color_table.txt文件卵凑,然后在appdelegate調(diào)用[[DKColorTable sharedColorTable] setFile:@"theme_color_table.txt"]; 注意如果使用系統(tǒng)自帶的編輯軟件編輯theme_color_table.txt 的話,可能會出現(xiàn)空格導(dǎo)致崩潰而且一般看不出來胜臊,最好用專用的文字編輯軟件去添加新的配置勺卢。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市象对,隨后出現(xiàn)的幾起案子黑忱,更是在濱河造成了極大的恐慌,老刑警劉巖甫煞,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異抚吠,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)弟胀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進(jìn)店門喊式,熙熙樓的掌柜王于貴愁眉苦臉地迎上來萧朝,“玉大人,你說我怎么就攤上這事检柬∶吵希” “怎么了?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵厕吉,是天一觀的道長酱固。 經(jīng)常有香客問我,道長头朱,這世上最難降的妖魔是什么运悲? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮项钮,結(jié)果婚禮上班眯,老公的妹妹穿的比我還像新娘。我一直安慰自己烁巫,他們只是感情好署隘,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著亚隙,像睡著了一般磁餐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上阿弃,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天诊霹,我揣著相機(jī)與錄音,去河邊找鬼渣淳。 笑死脾还,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的入愧。 我是一名探鬼主播鄙漏,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼棺蛛!你這毒婦竟也來了怔蚌?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤鞠值,失蹤者是張志新(化名)和其女友劉穎媚创,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體彤恶,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡钞钙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年鳄橘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片芒炼。...
    茶點(diǎn)故事閱讀 39,795評論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡瘫怜,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出本刽,到底是詐尸還是另有隱情鲸湃,我是刑警寧澤,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布子寓,位于F島的核電站暗挑,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏斜友。R本人自食惡果不足惜炸裆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一鲜屏、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧惯殊,春花似錦也殖、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽冻璃。三九已至损合,卻和暖如春省艳,著一層夾襖步出監(jiān)牢的瞬間跋炕,已是汗流浹背律适。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留纠修,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓了牛,卻偏偏與公主長得像辰妙,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子密浑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內(nèi)容