0、前言
随着iOS13的普及,大多数的APP都已经适配了暗黑模式,网络上关于暗黑模式适配的文章也很多,基本看几篇就能解决掉iOS13暗黑模式的适配。我看了大部分的文章,基本都是对暗黑模式通用的介绍和适配,一些实际项目中的具体细节却很少提及,所以此篇文章算是对于其他暗黑模式适配的补充,力求能做到完美适配暗黑模式。PS:如果你没看过其他的暗黑模式适配文章,那么你在看此文章前需要先去看一下其他关于暗黑模式适配的文章,此文章默认你是已经知道暗黑模式需要怎么适配了的。
1、LaunchScreen.storyboard
某些APP虽然适配了暗黑模式,但是对于启动页却没有进行适配。试想一下,当你使用暗黑模式在晚上打开APP的时候,本来其他的都是深色的突然被启动页的白色背景图片或者亮色背景闪了几下,眼睛会不会觉得难受。所以,建议大家如果你们的APP是亮色背景的话,那么建议你适配暗黑模式的时候也要考虑一下对启动图进行适配。为什么我在这里不说launchImage呢,因为根据苹果的规定,2020年4月份的时候所有的APP必须使用LaunchScreen才能提交APP,所以,现在适配的时候尽快替换成LaunchScreen。LaunchScreen适配暗黑模式也挺简单的,只需要点击下面的模式进行切换就能行。
需要注意的是:当你由launchImage换成LaunchScreen以后,或者是已经适配了暗黑模式但是就是看不到效果的时候,这是正常的,因为启动图被缓存了,这时候卸载APP在试试,如果还是不行,那么多卸载几次试试,或者换台手机试试,一定要相信自己。我在适配这个的时候就出现了一直不行,然后我以为是不能这样适配,后面用另外一台没有安装过APP的手机就可以显示出来。PS:我没有试过在Assets里面弄暗黑模式的和正常模式的图片,然后在LaunchScreen放一张图片的方式,因为我开始这样弄,但是由于缓存的原因一直没出来,我以为这样不行,所以换成点击下面的style设置去了。大家可以试试直接像其他图片适配一样进行适配可不可行。
2、WKWebview适配
现在大部分需要注册登录的APP都有一个隐私协议,而这个网页通常是使用WKWebview进行加载的(说到这里在提醒大家一下:webview也被废弃了,所以大家快转换到WKWebview上来)。这时候如果大家能叫前端帮忙适配,那肯定非常省事了。但是如果需要自己进行适配,那么也是可以的。核心就是通过JS代码去动态的修改HTML的背景色。先上代码在进行解释:
#import "ViewController.h"
#import <WebKit/WebKit.h>
@interface ViewController ()<WKNavigationDelegate>
@property (nonatomic, strong) WKWebView *webView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self loadHtmlWithWKView];
}
-(void)loadHtmlWithWKView{
WKWebViewConfiguration *wkWebconfigura = [[WKWebViewConfiguration alloc]init];
WKWebView *wkView = [[WKWebView alloc]initWithFrame:self.view.bounds configuration:wkWebconfigura];
[wkView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://juejin.im/welcome/ios"]]];
wkView.navigationDelegate = self;
self.webView = wkView;
[self.view addSubview:wkView];
self.webView.hidden = YES;
}
//navigationDelegate 当网页加载完毕后会调用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
NSString *backgroundColor = @"";
NSString *labelColor = @"";
if (@available(iOS 13.0, *)) {
if (UITraitCollection.currentTraitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {
backgroundColor = @"\"#001A1A\"";
labelColor = @"'#FF0000'";
}else{
backgroundColor = @"\"#FFFFFF\"";
labelColor = @"'#666666'";
}
} else {
self.webView.hidden = NO;
return;
}
//写入JS代码
[self.webView evaluateJavaScript:[NSString stringWithFormat:@"document.body.style.backgroundColor=%@",backgroundColor] completionHandler:nil];
[self.webView evaluateJavaScript:[NSString stringWithFormat:@"document.getElementsByTagName('body')[0].style.webkitTextFillColor=%@",labelColor] completionHandler:nil];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.webView.hidden = NO;
});
}
@end
核心思想就是通过JS代码去动态的修改网页的背景颜色和文字颜色。在webView:(WKWebView *)webView didFinishNavigation的时候进行当前模式的判断,在通过JS代码进行修改网页的颜色。有人可能会问,为什么不用WKUserScript去进行设置了,我试过了,不起作用。用下面的同一句代码进行设置,没有任何反应,我以为是因为后加载的网页覆盖掉了之前设置的背景颜色,说以在开始的JS代码里面加入了!important,结果也是不行的。为什么先对webView进行隐藏呢,这是因为我的APP隐私协议的背景颜色默认就是白色的,所以加载的时候会先显示白色,然后马上闪到我设置的颜色,对于用户来说,体验不是很好,所以先进行隐藏,而进行0.5s的延时在显示是因为那时候还没设置完,所以有时候会出现没改过来,或者是也会出现闪现的情况。下面看下效果:
修改成功,但是由于示例的li也是有背景颜色的,而我们修改的是body的背景,所以会有白色的cell。可以看到勾选swift/flutter的背景就是我们设置的背景,而我们的隐私协议一般都是P标签组成的,所以如果你的隐私协议修改body的背景不成功的话可以具体针对你的具体需求进行修改。
3轮播图(网络图片)的适配
对于图片的适配,大多数的做法是准备两张图片,一张是暗黑模式的,一张是正常模式的。但是对于网络上(公司服务器)拿到的轮播图或者网络图片,这些要用两张的话个人觉得有点麻烦了,如果是公司的图片UI需要准备两张倒是可以实现,但是如果是一些其他的图片,譬如用户自己上传的图片,那么我们是无法进行修改的。所以我的做法也很简单,在原来的imageView上面加盖一个蒙版就行,当用户切换到暗黑模式的时候把蒙版打开,这样可以调低图片的亮度值,假如是一张亮色的图片,因为有了蒙版也不会至于那么刺眼。上代码:(由于对比显示,所以我没有用图片直接设置imageView的背景为红色)
UIImageView *imageView = [[UIImageView alloc] init];
imageView.backgroundColor = [UIColor redColor];
imageView.frame = CGRectMake(0, 100, self.view.frame.size.width, 300);
[self.view addSubview:imageView];
UIView *backView = [[UIView alloc] init];
backView.frame = imageView.frame;
backView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.5];
[self.view addSubview:backView];
这样一对比就会发现加了蒙版的视觉效果不会那么刺眼,我的透明度设置的是0.5,你可以根据你们公司的需求进行设置即可。这样的话也算是完成了网络图片或者轮播图的暗黑模式适配了,
BUT:因为你加了蒙版,所以如果你后面的view或者是imageView有手势的话会失效
所以我们需要对点击到蒙版上的这个事件进行传递,详细的相关资料大家可以自行去搜索。我只告诉你最简单的解决方法,可能会有不严谨的地方。这时候我们只需要自定义一个view,然后在hitTest:(CGPoint)point withEvent:(UIEvent *)event里面让当前的这个蒙版view不响应手势即可。
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
UIView *view = [super hitTest:point withEvent:event];
if (view== self) {
return nil;
}
return [super hitTest:point withEvent:event];
}
本文只是默认了当前用户是在暗黑模式下的,实际开发中大家还需要用户在当前页面切换了模式,这个时候就需要在具体的界面监听下面这个方法
-(void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection{
//注意:这里返回的是前一次的状态
[super traitCollectionDidChange:previousTraitCollection];
if (@available(iOS 13.0, *)) {
if (previousTraitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {
self.backView.hidden = YES;
}else if (previousTraitCollection.userInterfaceStyle == UIUserInterfaceStyleLight){
self.backView.hidden = NO;
}
} else {
self.backView.hidden = YES;
}
}
但是需要注意的是这个方法显示的是前一次的状态。
至此,本文提到的关于暗黑模式的适配全部完成,有了这些以后,整个APP才算得上是完全适配了暗黑模式吧,而不是有一部分是深色的,有些地方却又是亮色的。