iOS 悼念日模式

清明节要到了,app要上悼念日模式,整体的风格要求变成灰色,之前看过腾讯新闻实现过类似的功能,这回终于要在自己app上实现了,而且要做成根据接口控制


安卓有系统设置可以几行代码就实现

iOS 这里没有类似的系统api 就只能自己想办法实现了,思路大概就是俩种

  • 根据接口开关,替换全部控件的颜色

  • 使用runtime替换所有控件的颜色赋值方法

第一种工作量大,而且不现实,不说iOS原生控件,WKwebView的颜色也不能控制,于是直接开始第二种思路


iOS UIKIT中常用控件为 button、imageView、lable、view等,设置颜色 大多是setBackgroundColor、textColor等方法,直接使用runtime 的方法替换来实现

方法替换代码

    Class class = [self class];
    
    SEL originalSelector = @selector(setBackgroundColor:);
    SEL swizzledSelector = @selector(lh_setButtonBackgroundColor:);
    
    Method originalMethod = class_getInstanceMethod(class, originalSelector);
    Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
    BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
    if (didAddMethod) {
        class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
    } else {
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }

tips

创建常用控件的分类,获取控件的实例方法时使用以下api

 Class class = [self class];
    
Method originalMethod = class_getInstanceMethod(class, @selector(setBackgroundColor:));

获取控件的类方法时使用以下api

Class cls = object_getClass(self);

Method originMethod = class_getClassMethod(cls, @selector(imageNamed:));

控件替换之后,再替换颜色赋值方法,创建color分类,从根本上把颜色替换成自己想要的颜色

Class cls = object_getClass(self);
    
    //将系统提供的colorWithRed:green:blue:alpha:替换掉
    Method originMethod = class_getClassMethod(cls, @selector(colorWithRed:green:blue:alpha:));
    Method swizzledMethod = class_getClassMethod(cls, @selector(lg_colorWithRed:green:blue:alpha:));
    [self swizzleMethodWithOriginSel:@selector(colorWithRed:green:blue:alpha:) oriMethod:originMethod swizzledSel:@selector(lg_colorWithRed:green:blue:alpha:) swizzledMethod:swizzledMethod class:cls];
    
    //将系统提供的colors也替换掉
    NSArray *array = [NSArray arrayWithObjects:@"redColor",@"greenColor",@"blueColor",@"cyanColor",@"yellowColor",@"magentaColor",@"orangeColor",@"purpleColor",@"brownColor",@"systemBlueColor",@"systemGreenColor", nil];
    
    for (int i = 0; i < array.count ; i ++) {
        SEL sel = NSSelectorFromString(array[i]);
        SEL lg_sel = NSSelectorFromString([NSString stringWithFormat:@"lg_%@",array[i]]);
        Method originMethod = class_getClassMethod(cls, sel);
        Method swizzledMethod = class_getClassMethod(cls, lg_sel);
        [self swizzleMethodWithOriginSel:sel oriMethod:originMethod swizzledSel:lg_sel swizzledMethod:swizzledMethod class:cls];
    }

之后就是图片,之前的想法是给所有图片都加一层灰色的滤镜,但是在网上找到了改变图片颜色的方法,(其实和滤镜算法差不多,都是改变位图的三rgb三元素)然后直接替换imageView的setImage:方法,返回灰色处理过后的图片

 //交换方法
    Class class = [self class];
    
    SEL originalSelector = @selector(setImage:);
    SEL swizzledSelector = @selector(swizzled_setImage:);
    
    Method originalMethod = class_getInstanceMethod(class, originalSelector);
    Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
    BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
    if (didAddMethod) {
        class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
    } else {
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }

替换图片的时候出现了一个问题 ,底部tabbarItem 上的图片变成了黑色,于是在替换的image 方法上使用imageWithRenderingMode模式,展示原样的图片

imageWithRenderingMode

再之后就是webView里面内容的置灰,在WKwebview里面注入js代码
,但是由于我的WKwebview里面写了跟js交互的代码,所以这段代码没有用runtime卸载分类里面 ,而是直接写在了我的WKWebViewController里面的WKWebView初始化里面

    NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
    NSString * change = [userDefault objectForKey:@"CHANGEGRAYMODEFORAPP"];
        
    WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
    WKUserContentController *userController = [[WKUserContentController alloc] init];
    configuration.userContentController = userController;
    
    if ([safeString(change) isEqualToString:@"1"]) {
        //悼念日模式 替换wkView整体主题色
        [userController addUserScript:[self getJsStr]];
    }

-(WKUserScript *)getJsStr{
    NSString *jScript = @"var filter = '-webkit-filter:grayscale(100%);-moz-filter:grayscale(100%); -ms-filter:grayscale(100%); -o-filter:grayscale(100%) filter:grayscale(100%);';document.getElementsByTagName('html')[0].style.filter = 'grayscale(100%)';";
    // 注入
    WKUserScript *wkUScript = [[WKUserScript alloc] initWithSource:jScript injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
    return wkUScript;
}

再之后就是导航栏的颜色变换
由于项目是了oc与swift混编,使用了多个navagationVc,然而在swift 的导航栏中 runtime 的颜色变换 并没有生效
于是导航栏的颜色也是使用本地开关设置的

NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
    NSString * change = [userDefault objectForKey:@"CHANGEGRAYMODEFORAPP"];
    if ([safeString(change) isEqualToString:@"1"]) {
        //悼念日模式 变换导航栏颜色
        self.navigationBar.tintColor = [UIColor lightGrayColor];
    }

最后就是要使用接口来控制是否展示悼念日模式,于是把接口写在了最前面的didFinishLaunchingWithOptions方法里面
到这里 基本上就算是完成了,

tips

使用storyBoard画的页面 会有imageView颜色不变换问题,解决办法是把控件的属性拉出来 ,手动再赋值一遍

 self.bgView.image = UIImage.init(named: "Icon_Login")

由于需要显示控制,于是在每个分类创建了个类方法

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface UIColor (LhGray)

+(void)lh_colorSwizzldColorMethedWith:(BOOL)changeGray;

@end

NS_ASSUME_NONNULL_END

之后再接口中判断是否显示

//悼念日模式开启
                [UIImageView lh_imageViewSwizzldMethedWith:true];
                //[WKWebView lh_WKWebViewWizzldMethedWith:true];
                [UIColor lh_colorSwizzldColorMethedWith:true];
                [UIButton lh_buttonSwizzldMethedWith:true];
                [UINavigationBar lh_navigationBarSwizzldMethedWith:true];
                NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
                [userDefault setObject:@"1" forKey:@"CHANGEGRAYMODEFORAPP"];
                [userDefault synchronize];



效果如下

B8FAE3733E95F0A1682BDEA819B9F934.png

最后的最后感谢俩位作者提供的文章
iOS APP界面黑白化处理(灰度处理)(为悼念日准备)
iOS 一键哀悼模式(灰度色盲模式)

代码上传到了github 上 如果可以 希望能点个star 😁
传送门

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容