iOS技术交流ios实用开发技巧DevSupport

使用DKNightVersion实现夜间模式

2016-08-01  本文已影响2783人  HiIgor

概述

DKNightVersion是github上面一个用于实现iOS应用夜间模式和多种主题的开源库。github上面有两个star数较高的库,DKNightVersion和SwiftTheme。后者源码是用swift实现的,OC和Swift混编导致应用的体积大幅度增加,于是选择了DKNightVersion。

使用方法

举例说明,此处假设我们的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。

等等,能用别的方式来创建dk_XXXColorPicker吗,比如RGB数值?当然可以DKNightVersion提供了 DKColorPickerWithRGB(NSUInteger normal, ...)接口来根据色号生成dk_XXXColorPicker。以上我们的Theme有n种,那么我们就需要在在dk_XXXColorPicker里面传入n个代表颜色的参数。
也可以设置不同Theme下的图片。

DKImagePicker Examples
imageView.dk_image = DKImagePickerWithImages([UIImage imageNamed:@"white"], [UIImage imageNamed:@"black"]); // => imageView的image在日间模式、夜间模式分别为图片名为white、black代表的图片。

也有很多方法来生成dk_image,例如:DKImagePickersWithImageNames(@"white",@"black"),直接根据图片名来生成dk_image,等等。

设置好了不同Theme下的颜色和图片,如下代码即可:

Theme Switch
[DKNightVersionManager sharedManager].themeVersion = DKThemeVersionNormal;// or DKThemeVersionNight => 将当前的主题切换到日间模式或夜间模式。

实现思路

先看下上面的例子中用到的一些属性。

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;

从使用方法里面可以看到我们在设置给UI控件的DKColorPicker属性赋值时,传入了n个颜色。n个颜色对应了n中Theme,而且他们根据索引一一对应。

DKNightVersionManager是一个用于管理主题的单例。当[DKNightVersionManager sharedManager].themeVersion 发生改变时,也就是当前的Theme发生了个改变。会发一个通知告诉所有的设置过DKColorPicker的UI控件。
UI控件收到通知后去找DKNightVersionManager去拿到当前的Theme,根据Theme更新UI控件的相关属性(backgroundColor,tintColor, textColor, image等),这边是实现这个功能一个大体的思路。

DKColorPicker是什么?它并不是一个用来存color的数组,它的定义是这样的:

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

它是一个block,传入一个我们已经定义好了的Theme,这个block给出一个color,用以更新。DKImagePicker同理。
每个对象都有一个pickers属性

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

在第一次使用这个属性时,当前对象注册为 DKNightVersionThemeChangingNotification 通知的观察者。pickers属性只有在对象的某个DKColorPicker/DKImagePicker首次被赋值时才会被创建。

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:"];
}

当Theme发生变化时,DKNightVersionManager会发出通知,所有监听DKNightVersionThemeChangingNotification的对象调用night_update方法去更新色值和图片。实现如下:

notification action
- (void)night_updateColor {
    [self.pickers enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull selector, DKColorPicker  _Nonnull picker, BOOL * _Nonnull stop) {
        SEL sel = NSSelectorFromString(selector);
        // picker根据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:,根据selector生成方法,然后去更新对象的颜色,图片等。这个库已经包含了所有的原生UI控件的color和image属性,通过runtime,category给UI控件添加属性。

作者推荐我们使用如下的方式来创建DKColorPicker。在DKColorTable.txt中,配置我们需要的色值和主题,内容如下:

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分别对应三个主题。
那么通过 DKColorPickerWithKey(BG),生成对应三个主题的DKColoPicker,并且目前的Theme只能通过修改DKColorTable.txt的文件内容进行管理。

总结

上一篇下一篇

猜你喜欢

热点阅读