Dependendo do negócio, geralmente há dois requisitos para os produtos:
Requisito 1: Defina tudo como preto e branco
Requisito 2: Defina uma determinada interface como preto e branco
Implementação aproximada:
Opção um:
O servidor envia todas as imagens em preto (cinza) e a cor da fonte suporta entrega dinâmica
. Tudo bem se houver apenas uma interface, mas se você substituir todas as imagens, a carga de trabalho será muito grande
Opção II:
Envolve aproximadamente: imagem, cor do UILabel, cor do UIButton, webView, vídeo, etc.
Para imagem, UIImageView é geralmente usado para exibir, portanto, use o método exchange em tempo de execução para permitir que o método setImage: tome conta dele.
Em seguida, adicione um filtro à imagem no método privado
+ (void)load { Method customMethod = class_getInstanceMethod([self class], @selector(setImage:)); Método originMethod = class_getInstanceMethod([autoclasse], @selector(gl_setImage:)); method_exchangeImplementations(customMethod, originMethod);//方法交换}
- (void)gl_setImage:(UIImage *)image { //Se para preto e branco, 1 significa aberto 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 { //UIKBSplitImageView是为了键盘 if (image == nil || [self.superview isKindOfClass:NSClassFromString(@"UIKBSplitImageView")]) { return image; } //Aplicativo do CIPhotoEffectNoir// Aplicativo do CIPhotoEffectMono NSString *filterName = @"CIPhotoEffectMono"; CIFilter *filter = [CIFilter filterWithName:filterName]; CIImage *inputImage = [[CIImage alloc] initWithImage:image]; [filtro setValue:inputImage forKey:kCIInputImageKey]; CGImageRef cgImage = [self.filterContext createCGImage:filter.outputImage fromRect:[extensão da imagem de entrada]]; 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 acinzentado - classificação
Arquivo 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:)); Método originMethod = class_getInstanceMethod([autoclasse], @selector(initWithFrame:configuration:)); method_exchangeImplementations(customMethod, originMethod);//方法交换}
- (instancetype)gl_initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration
{ BOOL isOpenWhiteBlackModel = [[NSUserDefaults standardUserDefaults] boolForKey:@"kIsShowBlackWhiteModel"]; if (isOpenWhiteBlackModel) { // 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%)';"; // Nome do WKUserScript *wkUScript = [[WKUserScript alloc] initWithSource:jScriptjectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
WKUserContentController *wkUController = [[WKUserContentController alloc] init];
[wkUController addUserScript:wkUScript];
// Configuração
do WKWebViewConfiguration *wkWebConfig = [[WKWebViewConfiguration alloc] init];
wkWebConfig.userContentController = wkUController;
configuração = wkWebConfig;
WKWebView *webView = [self gl_initWithFrame:configuração do quadro:configuração];
retornar webView;
}
return [self gl_initWithFrame:configuração do quadro:configuração];
}
@end
Há um problema com a solução acima, porque é um método init de substituição, que fará com que o webView antes do switch seja 0 seja colorido e o webView após o switch seja 1 para ser cinza. Portanto, certifique-se de confirmar que o resultado da solicitação de alternar é antes de criar o webView
. ou posteriormente
H5 acinzentado - único
Pode ser acinzentado para um único H5
Igual ao código js acima:
BOOL isOpenWhiteBlackModel = [[NSUserDefaults standardUserDefaults] boolForKey:@"kIsShowBlackWhiteModel"];
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
WKUserContentController *userController = [[
WKUserContentController alloc]
init]; { //modo Memorial Day substitui o tema geral cor de 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%)';"; // Nome do WKUserScript *wkUScript = [[WKUserScript alloc] initWithSource:jScriptjectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES]; retornar wkUScript; }
Para outras classificações de UILabel, UIButton, etc., consulte:
https://github.com/GeLeis/App_NoirDemo
terceira solução:
O processamento de imagem é semelhante à Solução 2
, mas as cores de Label, View, etc. não são mais classificadas uma a uma e a classificação de Color é modificada diretamente
+ (void)load { //关键方法交换 Method customMethod = class_getClassMethod([self class], @selector(gl_colorWithRed:green:blue:alpha:)); Método originMethod = class_getClassMethod([autoclasse], @selector(colorWithRed:green:blue:alpha:)); method_exchangeImplementations(customMethod, originMethod);//方法交换}
+ (UIColor *)gl_colorWithRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha { // Se for modo monocromático (modo preto e branco), a média r, g, valor b //se preto e branco, 1 significa aberto BOOL isOpenWhiteBlackModel = [[NSUserDefaults standardUserDefaults] boolForKey:@"kIsShowBlackWhiteModel"]; if (isOpenWhiteBlackModel) { //r, g, b ajuste de peso para evitar ocorrência, 1 0 0, 0 1 0 ,0 0 1 the same result //0.2126, 0.7152, 0.0722 Esses três são calculados de acordo com a força do olho humano para o r, g, b percepção de superfície de três cores CGF brilho flutuante = (vermelho * 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 implementa app em modo preto e branco
Opção quatro:
Não mais pelo método de tempo de execução, mas adicione diretamente um filtro cinza à exibição
//Obtém valor de cor RGBA
CGFloat r,g,b,a;
[[UIColor lightGrayColor] getRed:&r green:&g blue:&b alpha:&a]; //
Cria
ID de filtro cls = NSClassFromString(@"CAFilter");
id filter = [cls filterWithName:@"colorMonochrome"];
//Definir os parâmetros do filtro
[filter setValue:@[@(r),@(g),@(b),@(a)] forKey:@"inputColor "] ;
[filter setValue:@(0) forKey:@"inputBias"];
[filter setValue:@(1) forKey:@"inputAmount"];
//Definir para a janela
self.window.layer.filters = [NSArray arrayWithObject: filtro];
Os valores de r, g, b e a podem ser modificados diretamente em vez de [UIColor lightGrayColor]
Se for apenas um determinado controlador A, A.view.layer.filters = [NSArray arrayWithObject:filter];
basta configurá-lo
A página do aplicativo iOS está esmaecida
Claro, existem outros filtros que podem ser usados
id cls = NSClassFromString(@"CAFilter");
id filtro = [cls filterWithName:@"colorSaturate"];
[filter setValue:@(0) forKey:@"inputAmount"];
//Configuração da janela
self.window.layer.filters = [NSArray arrayWithObject:filter];
CAFilter é um método privado da Apple, que pode ser rejeitado, portanto, este método não é usado
abordagem final
Adicionar uma exibição que não recebe eventos de clique
@interface ZRLandlordHPGrayView : UIView
@fim
@implementation ZRLandlordHPGrayView
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{ return nil; }
@fim
Em seguida, na interface que precisa exibir o modo preto e branco, adicione o seguinte método:
- (void)showGrayViewWithSuperView:(UIView *)superView
{ //Este método é usado para armazenar se é o modo preto e branco BOOL isOpenWhiteBlackModel = [[NSUserDefaults standardUserDefaults] boolForKey:@"kIsShowBlackWhiteModel"]; if (isOpenWhiteBlackModel) { if ( @available( iOS 12.0, *)) {//Somente compatível com ZRLandlordHPGrayView 12 e superior *overlay = [[ZRLandlordHPGrayView alloc] initWithFrame:superView.bounds]; overlay.userInteractionEnabled = NO; overlay.translatesAutoresizingMaskIntoConstraints = false; overlay.backgroundColor = [ UIColor grayColor]; overlay.layer.compositingFilter = @"saturationBlendMode"; [superView addSubview:overlay];
[superView bringSubviewToFront:overlay];
} }
}
Este método suporta apenas 12 e acima.
Depois de olhar para nosso aplicativo, há basicamente muito poucos abaixo de 12, então finalmente escolhi este método
Outros artigos de referência:
Discussão da solução de cinza da interface do iOS
Modo de dia de luto do iOS
usando magia negra no iOS para obter uma solução global de cinza de imagem com um clique
Interface do aplicativo iOS Processamento em preto e branco (processamento em escala de cinza) (preparado para o dia de luto)