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

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

DKNightVersion夜間模式實現(xiàn)的最基本原理:每一種類型的控件注冊通知,當用戶點擊夜間模式時,發(fā)送通知,然后各控件響應通知方法,更改顏色.

  1. 注冊通知,添加通知響應方法.通過給根類NSObject(必須是根類里)添加類別Night,在類別里添加屬性pickers.初始化pickers時,注冊通知.并在類別里添加通知響應方法- (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. 注冊通知時機.提供另外的設置背景色的方法dk_setBackgroundColorPicker.使用之前的屬性self.pickers,保存背景色,self.pickers在初始化時會注冊通知.

    - (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ā)送通知,更改主題.作者是通過提供一個@property (nonatomic, strong) DKThemeVersion *themeVersion;themeVersion屬性,在設置的時候發(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中有幾點是值得學習的:

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

相關閱讀更多精彩內容

友情鏈接更多精彩內容