iOS 悼念日模式

作者: 福尔摩罗 | 来源:发表于2021-04-01 17:31 被阅读0次

    清明节要到了,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 😁
    传送门

    相关文章

      网友评论

        本文标题:iOS 悼念日模式

        本文链接:https://www.haomeiwen.com/subject/qewtkltx.html