iOS 应用中的「夜间模式」怎么实现?

关注者
122
被浏览
7,553

9 个回答

这个问题很多解决方案,要根据你自己的需求去找一个合适的。

有一些开源的解决方案,比如:GitHub - Draveness/DKNightVersion: Integrate night mode/theme into your iOS app
也有一些可以加载主题的框架,比如专注颜色方面的:GitHub - ViccAlexander/Chameleon: Flat Color Framework for iOS (Obj-C & Swift)

恰好我前段时间有给自己的 app 做过一个夜间模式,更准确的说是支持了主题。思路非常的简单。这里我只讲颜色的问题,图片的问题大同小异。

有几个核心的原则:
1. 所有的颜色都配置化,比如我的主题被定义成这个样子:
{
    "statusbar": 0,
    "colors": {
        "tint": "#e74c3c",
        "theme": "#ffffff",
        "light": "#ecf0f1",
        "text": "#666666",
        "darktext": "#95a5a6",
        "separator": "#dddddd",
        "placeholder": "#bdc3c7",
        "red": "#e74c3c",
        "gray": "#b2b2b2"
    }
}
你也可以用 plist 去存,反正要把你界面里面会出现视觉全都配在文件里面。

2. 你每次去颜色,都去 manager 里面取,只要是和主题相关的,你就不要出现 magic number。这个 manager 会在单例初始化的时候加载一次你设定的主题,比如 light 或者 night,加载的是上面说的配置文件。
NSMutableDictionary<NSString *, UIColor *> *temp = [NSMutableDictionary dictionary];
[(NSDictionary *)json[@"colors"] enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSString * _Nonnull obj, BOOL * _Nonnull stop) {
    temp[key] = [UIColor colorWithHex:obj];
}];
_colors = [NSDictionary dictionaryWithDictionary:temp];
_statusBarStyle = [json[@"statusbar"] integerValue];
然后你每次取颜色都是从 manager 的字典里面去取:
+ (UIColor *)colorForKey:(NSString *)key {
    return [[PINThemeManager manager] colors][key] ?: [UIColor clearColor];
}

+ (UIColor *)lightColor {
    return [PINThemeManager colorForKey:@"light"];
}

+ (UIColor *)textColor {
    return [PINThemeManager colorForKey:@"text"];
}
这样的话,你就能在配置不同的时候,取到不同的颜色。而且之后要扩展也非常方便,你只要增加 key 就可以了。

3. 当用户点击切换主题的时候,要做几件事情:
A. 把新主题的配置文件名更新一下,ThemeManager reload 一下
B. 当前屏幕截图并把图片盖上去,界面刷新主题,然后把图片 fadeOut,这样会有一个两种主题融合交替的一个效果
C. 将主题变化的消息通过你擅长的任何一种方法通知到其他的界面,完成全部界面的主题更换

其实这是一个非常简单的思路,只要你之前的开发里面不是经常写 magic number,要把主题切换换上去很容易。
虽然没做过, 但也可以猜一下是要用到JSBinding以及Hydrid开发的一些知识.
比如我们解压软件解压QQ浏览器的ipa文件, 可以在Payload->mttlite右键显示包内容, 可以发现该文件下赫然有WebViewJavascriptBridge.js.txt这么一个文件, 我们大可以猜测QQ浏览器使用到了 WebViewJavascriptBridge这个第三方库.
然后在/res/javascript文件夹下可以发现mtt_nightmode.css这么一个文件, 从文件名我们可以猜测QQ浏览器是通过JS修改CSS实现的夜间模式.
打开该文件, 可以确认这一点:

具体怎样实现修改,就要看你的项目是怎么实现的了, 如果你的项目就是Web App加载一个网页, 那么想来用相应的API接口执行JS语句修改便是了;.
如果用到了Hybrid开发, 比如像唐巧这篇文章的说的:基于 CoreText 的排版引擎:基础, 显示内容的容器是用TextView做的, 那么你还要自己再做一个解析类, 用来做主题自定义类的解析. 或者参考RayWenderlich上的这篇文章:Core Text Tutorial for iOS: Making a Magazine App, 也是用到了Coretext, 内容信息都是以XML传输, 只是你要讲相关的排版的信息都提前写好, 不然会崩溃....(这个图文混排的例子切换到横屏就会闪退)
P.S. @钟颖Cyan , 关于这个问题 您能否放个Demo给我们学习学习?或者哪天在您的专栏讲一讲, 以供我等菜鸟学习?