领导让调研下黑(灰)白化实现方案,自己调研了两天,根据网上资料,做下记录 只是学习过程中的记录,还是写作者牛逼🐂,参考资料会附在文章中
根据业务不一样,大致产品会有两种需求:
- 需求1:全部设置为黑白色
- 需求2:某个界面设置为黑白色
大致的实现方案:
方案一:
服务端下发所有黑(灰)图片,字体颜色支持动态下发 这个,如果是只有某个界面还好,如果是全量替换图片,工作量太大
方案二:
里面大致涉及到:image、UILabel的color、UIButton的Color、webView、Video等等
对于image,一般都是使用UIImageView去显示,因此,利用runtime里面的方法交换,让setImage:方法走自己的。 然后在私有方法里面实现对图片添加滤镜
+ (void)load {
Method customMethod = class_getInstanceMethod([self class], @selector(setImage:));
Method originMethod = class_getInstanceMethod([self class], @selector(gl_setImage:));
method_exchangeImplementations(customMethod, originMethod);
}
- (void)gl_setImage:(UIImage *)image {
BOOL isOpenWhiteBlackModel = [[NSUserDefaults standardUserDefaults] boolForKey:@"kIsShowBlackWhiteModel"];
if (isOpenWhiteBlackModel == 1) {
[self gl_setImage:[self gl_grayImage:image]];
} else {
[self gl_setImage:image];
}
}
- (UIImage *)gl_grayImage:(UIImage *)image {
if (image == nil || [self.superview isKindOfClass:NSClassFromString(@"UIKBSplitImageView")]) {
return image;
}
NSString *filterName = @"CIPhotoEffectMono";
CIFilter *filter = [CIFilter filterWithName:filterName];
CIImage *inputImage = [[CIImage alloc] initWithImage:image];
[filter setValue:inputImage forKey:kCIInputImageKey];
CGImageRef cgImage = [self.filterContext createCGImage:filter.outputImage fromRect:[inputImage extent]];
UIImage *resultImg = [UIImage imageWithCGImage:cgImage];
CGImageRelease(cgImage);
return resultImg;
}
- (CIContext *)filterContext {
CIContext *con = objc_getAssociatedObject(self, @selector(filterContext));
if (!con) {
con = [[CIContext alloc] initWithOptions:nil];
self.filterContext = con;
}
return con;
}
- (void)setFilterContext:(CIContext *)filterContext {
objc_setAssociatedObject(self, @selector(filterContext), filterContext, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
H5变灰—分类
WKWebView+blackWhiteModel.m文件:
#import "WKWebView+blackWhiteModel.h"
#import <objc/runtime.h>
@implementation WKWebView (blackWhiteModel)
+ (void)load {
Method customMethod = class_getInstanceMethod([self class], @selector(gl_initWithFrame:configuration:));
Method originMethod = class_getInstanceMethod([self class], @selector(initWithFrame:configuration:));
method_exchangeImplementations(customMethod, originMethod);
}
- (instancetype)gl_initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration
{
BOOL isOpenWhiteBlackModel = [[NSUserDefaults standardUserDefaults] boolForKey:@"kIsShowBlackWhiteModel"];
if (isOpenWhiteBlackModel) {
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 gl_initWithFrame:frame configuration:configuration];
return webView;
}
return [self gl_initWithFrame:frame configuration:configuration];
}
@end
iOS APP界面黑白化处理(灰度处理)(为悼念日准备)
上述方案有个问题,因为是替换的init方法,会导致在开关为0之前的webView都是彩色、开关为1之后的webView都是灰色 因此,务必确认,请求是否开关的结果在创建webView之前,还是之后
H5变灰—单个
可以针对单个的H5做变灰处理
跟上面的js代码都一样:
BOOL isOpenWhiteBlackModel = [[NSUserDefaults standardUserDefaults] boolForKey:@"kIsShowBlackWhiteModel"];
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
WKUserContentController *userController = [[WKUserContentController alloc] init];
configuration.userContentController = userController;
if (isOpenWhiteBlackModel) {
[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;
}
iOS 悼念日模式
其他UILabel、UIButton等的分类可参考:
https://github.com/GeLeis/App_NoirDemo
方案三:
图片处理与方案二类似 而Label、View等的color不再一个一个做分类处理,直接修改Color的分类
+ (void)load {
Method customMethod = class_getClassMethod([self class], @selector(gl_colorWithRed:green:blue:alpha:));
Method originMethod = class_getClassMethod([self class], @selector(colorWithRed:green:blue:alpha:));
method_exchangeImplementations(customMethod, originMethod);
}
+ (UIColor *)gl_colorWithRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha {
BOOL isOpenWhiteBlackModel = [[NSUserDefaults standardUserDefaults] boolForKey:@"kIsShowBlackWhiteModel"];
if (isOpenWhiteBlackModel) {
CGFloat brightness = (red * 0.2126 + 0.7152 * green + 0.0722 * blue);
return [self gl_colorWithRed:brightness green:brightness blue:brightness alpha:alpha];
}
return [self gl_colorWithRed:red green:green blue:blue alpha:alpha];
}
iOS 实现app黑白模式
方案四:
不再通过runtime的方法,而是直接为view添加灰色滤镜
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"];
self.window.layer.filters = [NSArray arrayWithObject:filter];
r, g, b, a的值都可以直接修改,而非必须是[UIColor lightGrayColor]
如果只是某个控制器A,则设置A.view.layer.filters = [NSArray arrayWithObject:filter]; 即可
iOS App页面置灰
当然,还有其他filter可以供使用
id cls = NSClassFromString(@"CAFilter");
id filter = [cls filterWithName:@"colorSaturate"];
[filter setValue:@(0) forKey:@"inputAmount"];
self.window.layer.filters = [NSArray arrayWithObject:filter];
CALayer 的 filters
其他参考文章: iOS界面置灰方案讨论 iOS 悼念日模式 在iOS使用黑魔法实现一键全局图片变灰白的一种方案 iOS APP界面黑白化处理(灰度处理)(为悼念日准备)
CALayer 的 filters CAFilter
|