一、开发环境

Xcode11 正式版
iOS13 beta版本
Mac系统: 10.15 beta版本

二、适配原理

  • 将同一个资源,创建出两种模式的样式。系统根据当前选择的样式,自动获取该样式的资源。
  • 每次系统更新样式时,应用会调用当前所有存在的元素调用对应的一些重新方法,进行重绘视图,可以在对应的方法做相应的改动

三、资源适配

step1、颜色适配 通过 Assets 配置

在 iOS 11和 Xcode 9 中,我们可以在 Images.xcassets 中添加颜色。
现在我们可以为颜色再配置一个用于暗黑模式的对应的颜色。

我们可以选择 (原彩,深色) 或者 (原彩,深色,夜览)

step2、图片适配

打开Assets.xcassets,新建一个Image set,打开右侧工具栏,点击最后一栏,找到Appearances,同样可以选择 (原彩,深色) 或者 (原彩,深色,夜览),然后在对应的位置添加图片

四、代码适配

step1、UIColor 适配 语义化颜色介绍加代码展示

iOS13 之前 UIColor只能表示一种颜色,而从 iOS13 开始UIColor是一个动态的颜色,在Light Mode和Dark Mode可以分别设置不同的颜色。
iOS13系统提供了一些动态颜色。苹果引入了全新系统颜色和一套根据颜色使用目的而约定颜色命名的语义化颜色

#pragma mark - 语义化颜色
@property (class, nonatomic, readonly) UIColor *systemBrownColor
@property (class, nonatomic, readonly) UIColor *systemIndigoColor
@property (class, nonatomic, readonly) UIColor *systemGray2Color
@property (class, nonatomic, readonly) UIColor *systemGray3Color
@property (class, nonatomic, readonly) UIColor *systemGray4Color
@property (class, nonatomic, readonly) UIColor *systemGray5Color
@property (class, nonatomic, readonly) UIColor *systemGray6Color
@property (class, nonatomic, readonly) UIColor *labelColor
@property (class, nonatomic, readonly) UIColor *secondaryLabelColor
@property (class, nonatomic, readonly) UIColor *tertiaryLabelColor
@property (class, nonatomic, readonly) UIColor *quaternaryLabelColor
@property (class, nonatomic, readonly) UIColor *linkColor
@property (class, nonatomic, readonly) UIColor *placeholderTextColor
@property (class, nonatomic, readonly) UIColor *separatorColor
@property (class, nonatomic, readonly) UIColor *opaqueSeparatorColor
@property (class, nonatomic, readonly) UIColor *systemBackgroundColor
@property (class, nonatomic, readonly) UIColor *secondarySystemBackgroundColor
@property (class, nonatomic, readonly) UIColor *tertiarySystemBackgroundColor
@property (class, nonatomic, readonly) UIColor *systemGroupedBackgroundColor
@property (class, nonatomic, readonly) UIColor *secondarySystemGroupedBackgroundColor
@property (class, nonatomic, readonly) UIColor *tertiarySystemGroupedBackgroundColor
@property (class, nonatomic, readonly) UIColor *systemFillColor
@property (class, nonatomic, readonly) UIColor *secondarySystemFillColor
@property (class, nonatomic, readonly) UIColor *tertiarySystemFillColor
@property (class, nonatomic, readonly) UIColor *quaternarySystemFillColor              

IOS13系统UIColor增加了两个初始化方法,使用以下方法可以创建动态UIColor
注:一个是类方法,一个是实例方法,两个方法如下:

+ (UIColor *)colorWithDynamicProvider:(UIColor * (^)(UITraitCollection *traitCollection))dynamicProvider
- (UIColor *)initWithDynamicProvider:(UIColor * (^)(UITraitCollection *traitCollection))dynamicProvider

可以在 block 中判断 traitCollection.userInterfaceStyle,根据系统模式设置返回的颜色。userInterfaceStyle,是一个枚举类型,会告诉我们当前是LightMode还是DarkMode

typedef NS_ENUM(NSInteger, UIUserInterfaceStyle) {UIUserInterfaceStyleUnspecified,UIUserInterfaceStyleLight,UIUserInterfaceStyleDark,
} API_AVAILABLE(tvos(10.0)) API_AVAILABLE(ios(12.0)) API_UNAVAILABLE(watchos);

例子

UIColor *color = [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull traitCollection) {if (traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {return [UIColor blackColor];} else {return [UIColor whiteColor];}}];

step2、CGColor 适配

我们知道iOS13后,UIColor能够表示动态颜色,但是CGColor依然只能表示一种颜色,那么对于CALayer等对象如何适配暗黑模式呢?这里提供两个方法供大家参考:
(1)、通过方法resolvedColorWithTraitCollection得到对应UIColor,再将UIColor转换为CGColor

UIColor *resolvedColor = [dyColor resolvedColorWithTraitCollection:previousTraitCollection];
layer.backgroundColor = resolvedColor.CGColor;

(2)、直接设置为一个动态UIColor的CGColor即可

- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {[super traitCollectionDidChange:previousTraitCollection];UIColor *dyColor = [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull trainCollection) {if ([trainCollection userInterfaceStyle] == UIUserInterfaceStyleLight) {return [UIColor redColor];} else {return [UIColor greenColor];}}];layer.backgroundColor = dyColor.CGColor;
}

⚠️ 注意!!! 我们需要为layer设置一个基本颜色,因为两个方法都是在traitCollectionDidChange中设置layer的颜色,那么如果没有发生模式切换,layer将会没有颜色

五、获取当前模式以及UITraitCollection介绍,监听模式切换

在 iOS 13 中,我们可以通过 UITraitCollection 来判断当前系统的模式。UIViewUIViewController 、UIScreen、UIWindow 都已经遵从了UITraitEnvironment 这个协议,因此这些类都拥有一个叫做 traitCollection 的属性,在这些类中,我们可以这样去判断当前 App 的颜色模式:

BOOL isDark = (self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark);

另外,我们还可以通过 UITraitCollection.current 这个属性来获取当前 App 的颜色模式但是并不是所有的时候获取的都是正确的,只有在下面这些方法中,才可以放心的使用这个属性:

还没适配完又不想给用户看,可以先暂时全局关闭暗黑模式:在 Info.plist 文件中,添加 key 为 User Interface Style,类型为 String,value 设置为 Light 即可。
有时我们需要监听系统模式的变化,并作出响应
那么我们就需要在需要监听的viewController中,重写下列函数

#pragma mark - 监听系统模式变化
// ⚠️ 参数为变化前的traitCollection
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection;#pragma mark - 判断两个UITraitCollection对象是否不同
- (BOOL)hasDifferentColorAppearanceComparedToTraitCollection:(UITraitCollection *)traitCollection;

示例代码

- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {[super traitCollectionDidChange:previousTraitCollection];// trait发生了改变if ([self.traitCollection hasDifferentColorAppearanceComparedToTraitCollection:previousTraitCollection]) {// 执行操作}
}

在 iOS 13中,UIView、UIViewController 、UIWindow 有了一个 overrideUserInterfaceStyle 的新属性,可以覆盖系统的模式

单个页面或视图关闭暗黑模式,设置 overrideUserInterfaceStyle 为对应的模式,强制限制该视图与其子视图以设置的模式进行展示,不跟随系统模式改变进行改变。
示例代码

self.overrideUserInterfaceStyle = UIUserInterfaceStyleLight;

⚠️ 注意!!!

  • 当我们强行设置当前viewController为Dark Mode后,这个viewController下的view都是Dark Mode
  • 由这个ViewController present出的ViewController不会受到影响,依然跟随系统的模式
  • 要想一键设置App下所有的ViewController都是Dark Mode,请直接在Window上执行overrideUserInterfaceStyle
  • 对window.rootViewController强行设置Dark Mode也不会影响后续present出的ViewController的模式

六、扩展

step1、模糊效果

  • 在 iOS 中,我们创建模糊效果的 UIVisualEffectView 的代码也会有明确表面明暗的情况。我们需要让这些模糊效果随着系统模式的切换而切换。UIKit 提供了新的模糊样式且是动态的,会随着系统模式的改版而自动匹配。
  • 在利用 UIVisualEffectView 来创建一些类似模糊的效果时,不要设置类似 UIBlurEffectStyleExtraLight 这样带有明确颜色的效果,而是设置 UIKit 中新提供的动态样式的效果,比如 UIBlurEffectStyleSystemThinMaterialLight 或 UIBlurEffectStyleSystemThinMaterialDark。
UIBlurEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemMaterial];
UIVisualEffectView *effectView = [[UIVisualEffectView alloc] initWithEffect:effect];

step2、启动图

如果我们的 App 使用了 LaunchImage 作为启动屏,那么就应该考虑把 LaunchImage 换成 LaunchScreen.storyboard 了,因为在 Xcode 11 中 LaunchImage 并不能像普通的图片那样针对深色模式设置另外的一张图片。

step3、富文本

给 Attributed String 加上一个 foregroundColor 属性,设置动态的颜色即可。

[attr addAttribute:NSForegroundColorAttributeName value:[UIColor labelColor] range:NSMakeRange(10, 20)];

step4、调试 dark mode

storyboards 和 xib 文件,现在可以切换界面之间的样式是默认还是暗黑了。

在模拟器上,也可以直接切换暗黑模式进行调试了。

step5、模式切换打印

  • 模式切换时自动打印log,就不需要我们一次又一次的执行po命令了
  • 在Xcode菜单栏Product->Scheme->Edit Scheme
    选择Run->Arguments->Arguments Passed On Launch
    添加以下命令即可
  • UITraitCollectionChangeLoggingEnabled YES

step6、Demo地址 YQDarkModeDemo

iOS开发 DarkMode 暗黑模式相关推荐

  1. iOS 13 DarkMode 暗黑模式

    iOS 13终于引来了暗黑模式. 每当新特性的到来,iOS开发者们既紧张又有点小兴奋,怀揣着被虐的心态,让我们来看看暗黑模式到底是个啥. 虽然这是一个设计驱动的需求,但是本着一颗虔诚(暴躁)的心,我们 ...

  2. iOS开发关闭暗黑模式

    全局关闭暗黑模式 1.在info.plist文件中,添加UIUserInterfaceStyle key名字为User Interface Style 值为String, 2.将UIUserInter ...

  3. 微信联合苹果探索iOS系统的暗黑模式;iPhone SE 2于3月31日发布;Kotlin 1.3.70发布 | 极客头条...

    整理 | 郭芮 头图 | CSDN 下载自东方 IC 快来收听极客头条音频版吧,智能播报由标贝科技提供技术支持. 「极客头条」-- 技术人员的新闻圈! CSDN 的读者朋友们早上好哇,「极客头条」来啦 ...

  4. iOS开发的架构模式

    iOS开发的架构模式 0.VIPER 为了减轻Controller层负担的方法,而VIPER架构其实是将Controller再细分成三层,分别是View.Interactor.Presenter,已达 ...

  5. iOS 13.0 暗黑模式的适配

    一.暗黑模式的原理 将原本的资源文件,创建出两种不同的模式.根据不同的模式,自动获取该样式的资源. 每次切换系统模式的时候,系统会重新调用一些方法,重新赋值. 二.暗黑模式适配主要考虑的是: 1. 图 ...

  6. iOS 13适配——暗黑模式

    暗黑模式介绍 Implementing Dark Mode on iOS How To Adopt Dark Mode In Your iOS App Adopting iOS Dark Mode S ...

  7. iOS 开发 关闭黑暗模式

    在info.plist文件中加一条Appearance - Light, 如下图: 参考博客: iOS暗黑(dark)模式适配 IOS 开发之关闭暗黑模式

  8. iOS开发-简单工厂模式

    设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性.概念很长,iOS开发中最常 ...

  9. (iOS开发总结)MVC模式

    一.MVC 模式 MVC,即模型-视图-控制器(Model-View-Model),是软件开发中应用甚广的一种设计模式.其用意是将数据与视图分化,利用模型数据控制视图的显示,但两者的交互由控制器控制. ...

最新文章

  1. mysql 动态显示月份列_mysql 中动态显示列
  2. 系统指纹 中间指纹 web指纹 识别简介
  3. oracle 根据分隔符提取,oracle根据分隔符获取字符串
  4. python中如何打开csv文件_在Python中从CSV文件读取数据
  5. 框架:Mybatis中使用sql几种特殊情况
  6. wiki文档书写格式
  7. 曹大带我学 Go(12)—— 面向火焰图编程
  8. ES6-11 Symbol、iterator、forOf、typeArray
  9. 扎克伯格、张一鸣的技术“原罪”
  10. ggplot2作图详解:标尺(scale)设置
  11. 正态总体的样本均值与样本方差的分布定理
  12. 固定IP和自动IP切换bat脚本
  13. 如何随意复制网页上的文字
  14. 除PDF转换,写论文还需PDF编辑?迅读PDF大师告诉你答案
  15. CS224W-图神经网络 笔记5.3:Spectral Clustering - 谱图聚类的具体操作步骤
  16. 端云协同,打造更易用的AI计算平台
  17. iOS 边学边记 直播原理总结,从理论到实践
  18. 为什么看P1dB压缩,而不是2dB,3dB压缩
  19. 什么样的导师最坑学生?
  20. mysql引擎与优化

热门文章

  1. 几何分布的期望公式的推导
  2. 安装Ubuntu后的配置
  3. Win环境下配置PyTorch深度学习环境
  4. OKR是上下同欲的载体
  5. [unityshader]制作能量护盾以及简单互动
  6. 考研、考公还是找工作?别在大学因为迷茫这个问题浪费时间了
  7. 实用Python程序设计测验:数字统计
  8. 赵小楼《天道》《遥远的救世主》深度解析(9)肖亚文的“小心思和小算计”
  9. log4j2配置详情
  10. Windows HANDLE是什么