首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >iOS界面黑白实现

iOS界面黑白实现

原创
作者头像
莫空9081
修改2022-12-12 15:09:04
1.4K0
修改2022-12-12 15:09:04
举报
文章被收录于专栏:iOS 备忘录iOS 备忘录

背景

iOS APP界面黑白效果实现调研整理,总的来说网上目前有下面几种方法:

  • 针对H5网页:注入js代码
  • 针对APP原生界面:
    • 针对图片和颜色单独设置
      • hook UIImageView的setImage方法,添加UIImage的Category,生成灰色图片
      • hook UIColor的colorWithRed:green:blue:alpha:方法
    • 针对界面整体处理
      • 创建一个灰色view,设置不响应事件,然后添加在window最上层
      • 给App整体添加灰色滤镜

具体如下:

<!--more-->

实现

针对网页:

针对网页的处理:

  • 如果有基类,可以直接在基类初始化WKWebview的地方,添加如下代码:
  WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];

  // js脚本

  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];

  [config.userContentController addUserScript:wkUScript];
  • 如果没有基类,则通过Swizzle_Method实现:
  #import "WKWebView+Swizzle.h"

  @implementation WKWebView (Swizzle)

- (void)load {
  Class class = [self class];

  SEL originalSelector = @selector(initWithFrame:configuration:);

  SEL swizzleSelector = @selector(swizzleInitWithFrame:configuration:);

  Method originalMethod = class_getInstanceMethod(class, originalSelector);

  Method swizzleMethod = class_getInstanceMethod(class, swizzleSelector);

  method_exchangeImplementations(originalMethod, swizzleMethod);

  }

- (instancetype)swizzleInitWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration )configuration {
  // js脚本
  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];
               
  WKUserContentController *wkUController = [[WKUserContentController alloc] init];

     [wkUController addUserScript:wkUScript];

  // 配置对象

  WKWebViewConfiguration *wkWebConfig = [[WKWebViewConfiguration alloc] init];

  wkWebConfig.userContentController = wkUController;

  configuration = wkWebConfig;

  WKWebView *webView = [self swizzleInitWithFrame:frame configuration:configuration];

  return webView;
  }

  @end

针对APP原生界面的处理

  • 针对颜色和图片处理:

a. 针对图片的处理:大部分图片的显示都是最后都是调用UIImageViewsetImage方法,所以hook这个方法,在显示前生成灰色的图片,然后在赋值,代码如下:

hook UIImageViewsetImage方法

#import "UIImageView+Swizzle.h"

#import "UIImage+Category.h"

@implementation UIImageView (Swizzle)

+ (void)load {

    Class class = [self class];

    SEL originalSelector = @selector(setImage:);

    SEL swizzleSelector = @selector(swizzleSetImage:);

    Method originalMethod = class_getInstanceMethod(class, originalSelector);

    Method swizzleMethod = class_getInstanceMethod(class, swizzleSelector);

    method_exchangeImplementations(originalMethod, swizzleMethod);

}

- (void)swizzleSetImage:(UIImage *)image {
    UIImage *grayImage = [image anotherGrayImage];
    [self swizzleSetImage:grayImage];
}

@end

生成灰色图片的代码如下:

#import <UIKit/UIKit.h>

@interface UIImage (Category)

// 不建议使用,内存占用大,且在多图列表上滑动时,影响性能,造成卡顿

//- (UIImage *)grayImage;

// 推荐使用,内存相对小,不卡顿,需注意图片是否包含A通道(ARGB通道)

- (UIImage *)anotherGrayImage;

@end

// 参考https://blog.csdn.net/iOSxiaodaidai/article/details/113553395

#import "UIImage+Category.h"

@implementation UIImage (Category)

- (UIImage *)grayImage {
    CIImage *beginImage = [CIImage imageWithCGImage:self.CGImage];
    CIFilter *filter = [CIFilter filterWithName:@"CIColorControls"];
    [filter setValue:beginImage forKey:kCIInputImageKey];
    // 修改饱和度为0,范围0-2,默认为1
    [filter setValue:0 forKey:@"inputSaturation"];
    

    // 得到过滤后的图片

    CIImage *outputImage = [filter outputImage];

    // 转换图片,创建基于GPU的CIContext对象

    CIContext *context = [CIContext contextWithOptions:nil];

    CGImageRef cgImage = [context createCGImage:outputImage fromRect:[outputImage extent]];

    UIImage *newImage = [UIImage imageWithCGImage:cgImage];

    // 释放C对象

    CGImageRelease(cgImage);

    return newImage;

}

- (UIImage *)anotherGrayImage {
    // 注意这里图片的大小
    CGFloat scale = [UIScreen mainScreen].scale;
    NSInteger width = self.size.width * scale;
    NSInteger height = self.size.height * scale;
    

    // 第一步:创建颜色空间——图片灰度处理(创建灰度空间)

    CGColorSpaceRef colorRef = CGColorSpaceCreateDeviceGray();

    //第二步:颜色空间的上下文(保存图像数据信息)

    //参数1:内存大小(指向这块内存区域的地址)(内存地址)

    //参数2:图片宽

    //参数3:图片高

    //参数4:像素位数(颜色空间,例如:32位像素格式和RGB颜色空间,8位)

    //参数5:图片每一行占用的内存比特数

    //参数6:颜色空间

    //参数7:图片是否包含A通道(ARGB通道),注意这个参数

    CGContextRef context = CGBitmapContextCreate(nil, width, height, 8, 0, colorRef, kCGImageAlphaPremultipliedLast);

    // 释放内存

    CGColorSpaceRelease(colorRef);

    if (context == nil) {

        return nil;

    }
  
    //第三步:渲染图片(绘制图片)

    //参数1:上下文

    //参数2:渲染区域

    //参数3:源文件(原图片)(说白了现在是一个C/C++的内存区域)

    CGContextDrawImage(context, CGRectMake(0, 0, width, height), self.CGImage);

    //第四步:将绘制颜色空间转成CGImage(转成可识别图片类型)

    CGImageRef grayImageRef = CGBitmapContextCreateImage(context);

    //第五步:将C/C++ 的图片CGImage转成面向对象的UIImage(转成iOS程序认识的图片类型)

    UIImage *dstImage = [UIImage imageWithCGImage:grayImageRef];

    //释放内存

    CGContextRelease(context);

    CGImageRelease(grayImageRef);

    return dstImage;

}

@end

b. 针对颜色的处理:

所有颜色的设置,最终都会走UIColorcolorWithRed:green:blue:alpha:,所以通过hook这个方法,生成灰色的颜色返回并显示,代码如下:

  #import "UIColor+Swizzle.h"

  @implementation UIColor (Swizzle)

  + (void)load {

      Class class = [self class];

      SEL originalSelector = @selector(colorWithRed:green:blue:alpha:);

      SEL swizzleSelector = @selector(swizzle_colorWithRed:green:blue:alpha:);

      Method originalMethod = class_getClassMethod(class, originalSelector);

      Method swizzleMethod = class_getClassMethod(class, swizzleSelector);

      method_exchangeImplementations(originalMethod, swizzleMethod);

  }

  + (UIColor *)swizzle_colorWithRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha {

      CGFloat grayValue = 0.299*red + 0.587*green + 0.114*blue;

      UIColor *gray = [UIColor colorWithWhite:grayValue alpha:alpha];

      return gray;

  }

  @end
  • 针对界面整体处理

a. 方法一:创建一个灰色view,设置不响应事件,然后添加在window最上层

  #import <UIKit/UIKit.h>

  /// 最顶层视图,承载滤镜,自身不接受、不拦截任何触摸事件

  @interface UIViewOverLay : UIView

  @end

  #import "UIViewOverLay.h"

  @implementation UIViewOverLay

  - (instancetype)init {
      self = [super init];
      if (self) {
          [self setupSubviews];
      }
      return self;
  }

  - (instancetype)initWithFrame:(CGRect)frame {
      self = [super initWithFrame:frame];
      if (self) {
          [self setupSubviews];
      }
      return self;
  }

  - (void)setupSubviews {
      self.translatesAutoresizingMaskIntoConstraints = NO;
      self.backgroundColor = [UIColor lightGrayColor];
      self.layer.compositingFilter = @"saturationBlendMode";
  }

  - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
      // 不处理点击事件
      return nil;
  }

  @end

b. 方法二:给App整体添加灰色滤镜,同样加在window最上层

  //获取RGBA颜色数值

  CGFloat r,g,b,a;

  [UIColor lightGrayColor getRed:&r green:&g blue:&b alpha:&a];

  //创建滤镜

  id cls = NSClassFromString(@"CAFilter");

  id filter = cls filterWithName:@"colorMonochrome";

  //设置滤镜参数

  [filter setValue:@@(r),@(g),@(b),@(a) forKey:@"inputColor"];

  filter setValue:@(0) forKey:@"inputBias";

  filter setValue:@(1) forKey:@"inputAmount";

  //设置给window

  window.layer.filters = NSArray arrayWithObject:filter;

总结

iOS APP界面黑白效果实现,不建议图片和颜色单独分开设置,而大部分APP首页不是H5的。所以建议创建一个灰色view,设置不响应事件,然后添加在要置灰的页面或者全局window的最上层即可。

完整代码放在Github:GrayTheme_iOS

可通过CocoaPods安装:

pod 'GrayTheme'

参考

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 实现
    • 针对网页:
      • 针对APP原生界面的处理
      • 总结
      • 参考
      相关产品与服务
      图片处理
      图片处理(Image Processing,IP)是由腾讯云数据万象提供的丰富的图片处理服务,广泛应用于腾讯内部各产品。支持对腾讯云对象存储 COS 或第三方源的图片进行处理,提供基础处理能力(图片裁剪、转格式、缩放、打水印等)、图片瘦身能力(Guetzli 压缩、AVIF 转码压缩)、盲水印版权保护能力,同时支持先进的图像 AI 功能(图像增强、图像标签、图像评分、图像修复、商品抠图等),满足多种业务场景下的图片处理需求。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档