DKNightVersion夜間模式實(shí)現(xiàn)原理

DKNightVersion夜間模式實(shí)現(xiàn)原理

DKNightVersion夜間模式實(shí)現(xiàn)的最基本原理:每一種類(lèi)型的控件注冊(cè)通知,當(dāng)用戶(hù)點(diǎn)擊夜間模式時(shí),發(fā)送通知,然后各控件響應(yīng)通知方法,更改顏色.

  1. 注冊(cè)通知,添加通知響應(yīng)方法.通過(guò)給根類(lèi)NSObject(必須是根類(lèi)里)添加類(lèi)別Night,在類(lèi)別里添加屬性pickers.初始化pickers時(shí),注冊(cè)通知.并在類(lèi)別里添加通知響應(yīng)方法- (void)night_updateColor.

    @implementation NSObject (Night)
    
    - (NSMutableDictionary<NSString *, DKColorPicker> *)pickers {
        NSMutableDictionary<NSString *, DKColorPicker> *pickers = objc_getAssociatedObject(self, @selector(pickers));
        if (!pickers) {
            
            @autoreleasepool {
                // Need to removeObserver in dealloc
                if (objc_getAssociatedObject(self, &DKViewDeallocHelperKey) == nil) {
                    __unsafe_unretained typeof(self) weakSelf = self; // NOTE: need to be __unsafe_unretained because __weak var will be reset to nil in dealloc
                    id deallocHelper = [self addDeallocBlock:^{
                        [[NSNotificationCenter defaultCenter] removeObserver:weakSelf];
                    }];
                    objc_setAssociatedObject(self, &DKViewDeallocHelperKey, deallocHelper, OBJC_ASSOCIATION_ASSIGN);
                }
            }
    
            pickers = [[NSMutableDictionary alloc] init];
            objc_setAssociatedObject(self, @selector(pickers), pickers, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
            
            [[NSNotificationCenter defaultCenter] removeObserver:self name:DKNightVersionThemeChangingNotification object:nil];
    
            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(night_updateColor) name:DKNightVersionThemeChangingNotification object:nil];
        }
        return pickers;
    }
    
    - (void)night_updateColor {
        [self.pickers enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull selector, DKColorPicker  _Nonnull picker, BOOL * _Nonnull stop) {
            SEL sel = NSSelectorFromString(selector);
            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
                             }];
        }];
    }
    
    
  2. 注冊(cè)通知時(shí)機(jī).提供另外的設(shè)置背景色的方法dk_setBackgroundColorPicker.使用之前的屬性self.pickers,保存背景色,self.pickers在初始化時(shí)會(huì)注冊(cè)通知.

    - (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:"];
    }
    
  3. 發(fā)送通知,更改主題.作者是通過(guò)提供一個(gè)@property (nonatomic, strong) DKThemeVersion *themeVersion;themeVersion屬性,在設(shè)置的時(shí)候發(fā)送通知.

    - (void)setThemeVersion:(DKThemeVersion *)themeVersion {
        if ([_themeVersion isEqualToString:themeVersion]) {
            // if type does not change, don't execute code below to enhance performance.
            return;
        }
        _themeVersion = themeVersion;
    
        // Save current theme version to user default
        [[NSUserDefaults standardUserDefaults] setValue:themeVersion forKey:DKNightVersionCurrentThemeVersionKey];
        [[NSNotificationCenter defaultCenter] postNotificationName:DKNightVersionThemeChangingNotification
                                                            object:nil];
    
        if (self.shouldChangeStatusBar) {
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Wdeprecated-declarations"
            if ([themeVersion isEqualToString:DKThemeVersionNight]) {
                [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
            } else {
                [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault];
            }
    #pragma clang diagnostic pop
        }
    

}
```

DKNightVersion中有幾點(diǎn)是值得學(xué)習(xí)的:

  • 作者并沒(méi)有在每個(gè)控件初始化的時(shí)候注冊(cè)通知.在每個(gè)控件初始化的時(shí)候注冊(cè)通知不僅繁瑣,而且沒(méi)辦法進(jìn)行封裝.所以必須找到一個(gè)總?cè)肟?在那里進(jìn)行通知的注冊(cè).
  • 盡可能少的代碼侵入性,通過(guò)類(lèi)別可以實(shí)現(xiàn)最少的代碼侵入性.通過(guò)給根類(lèi)添加類(lèi)別,再通過(guò)runtime添加屬性.這樣就有了一個(gè)總?cè)肟?因?yàn)槊總€(gè)類(lèi)都是繼承自NSObject的.
  • 作者將通知的注冊(cè)和通知的發(fā)送都封裝在設(shè)置屬性里,很好的隱藏了實(shí)現(xiàn)的細(xì)節(jié).
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容