iOS黑(灰)白化实现方案

一个简单的首页黑屏技术方案的研究

Posted by poos on March 3, 2023

需求

一般情况下是遇到国事,需要灰屏显示。那么技术上如何实现呢:

根据业务不一样,大致产品会有两种需求:

需求1:全部设置为黑白色 需求2:某个界面(首页)设置为黑白色

技术方案

全黑的情况一般是全局处理,而不是针对每个ui组件处理了。根本上有两种处理方向:

  • 从下至上的 window 层,设置色彩过滤器

咱们就是个黑白显示容器

  • 从上至下的 view 层色彩过滤片覆盖

咱们搞个过滤眼睛

设置window黑色

通过给 window 的 layer 层进行颜色过滤设置即可。这个方案没有什么技术限制,直接设置即可。一个缺点是,基于全局 window 设置,如果是首页黑屏的情况,有页面动画会看起来不那么友好。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- (void)setLayerGrayFilter {
    //获取RGBA颜色数值
    static id filter;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        CGFloat r,g,b,a;
        [[UIColor whiteColor] getRed:&r green:&g blue:&b alpha:&a];
        //创建滤镜
        NSString *classStr = [self stringFromSecCharsMethod0];
        id cls = NSClassFromString(classStr);
        if (!cls) {return;}
        NSString *selStr = [self stringFromSecCharsMethod1];
        filter = [cls filterWithName:selStr];
        if (!filter) {return;}
        //设置滤镜参数
        [filter setValue:@[@(r),@(g),@(b),@(a)] forKey:[self stringFromSecCharsMethod2]];
        [filter setValue:@(0) forKey:[self stringFromSecCharsMethod3]];
        [filter setValue:@(1) forKey:[self stringFromSecCharsMethod4]];
    });
    //设置
    self.layer.filters = [NSArray arrayWithObject:filter];
}

添加一个滤镜

如果能够添加一个滤镜,并且能够随着 present,push 的动画出现消失,呢么可以实现更友好的体验。

先声明一个不响应点击的 view。

1
2
3
4
5
6
7
8
9
10
11
12
@interface MB_GrayFilterView : UIView

@end

@implementation MB_GrayFilterView

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    return nil;
}

@end

初始化

1
2
3
4
5
6
// @available(iOS 13.0, *)
GrayFilterView *overlay = [[GrayFilterView alloc] initWithFrame:[UIScreen mainScreen].bounds];
overlay.userInteractionEnabled = NO;
overlay.translatesAutoresizingMaskIntoConstraints = false;
overlay.backgroundColor = [UIColor blackColor];
overlay.layer.compositingFilter = [self stringFromSecCharsMethod5];

加入 widow

1
2
[[[UIApplication sharedApplication].delegate window] addSubview:nav_overView];
[[[UIApplication sharedApplication].delegate window] bringSubviewToFront:nav_overView];

处理滑动

1
2
3
4
5
6
7
8
9
10
11
12
-(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    BOOL currentIsPush = navigationController.viewControllers.count > navVCCount;
    id<UIViewControllerTransitionCoordinator> coor = viewController.transitionCoordinator;
    if (coor != nil) {
        [coor animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
            CGFloat x = [UIScreen mainScreen].bounds.size.width * (!currentIsPush) - [UIScreen mainScreen].bounds.size.width;
            gary_overView.frame = CGRectMake(x, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);
        } completion:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
            
        }];
    }
}

同样的 present 参考 ios present转场动画 ios 自定义转场动画

其他

一个本地混淆

本地混淆使用的系统方法,异或,先异或一次,使用时候再异或一次:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//NSString *method = @"";
//NSData *data = [method dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
//char *bs = malloc(sizeof(char) * data.length);
//memcpy(bs, data.bytes, data.length);
//static unsigned char chars[sizeof(bs)] = {0};
//for (int i = 0 ; i< data.length; i++) {
//    char c = bs[i] ^ 0x55;
//    chars[i] = c;
//    printf("0x%2x,",c);
//}
//printf("\n%s,",chars);

// CAFilter
- (NSString *)stringFromSecCharsMethod0 {
    unsigned char selByte[] = {0x16,0x14,0x13,0x3c,0x39,0x21,0x30,0x27,};
    return [self stringFromSecChars:selByte length:8];
}

// 使用mutable string来进行拼接,如果直接使用 stringWithCString会导致获取到 char[] 的上下文string,导致获取到的太长,或乱码。
- (NSString *)stringFromSecChars:(unsigned char [])charsByet length:(int)length {
    NSMutableString * muStr = [[NSMutableString alloc] init];
    for (int i = 0; i< length; i++) {
          char b = charsByet[i] ^ 0x55;\
        [muStr appendFormat:@"%c", b];
    }
    return muStr;
}

其他参考: Core Image Filter Reference