iOS13暗黑模式适配

根据苹果的⼀贯保持的⻛格,我们会特别简单、舒服的适配了它。 因此,苹果介绍的就是这三句句话。
Dark mode is a new look
It's easy to implement
Flexible and powerful

秉承Easy to implement 的风格 ,苹果提供了新的color对象帮我们快速实现简单的mode切换,苹果把它叫做-Dynamic colors, 如下图在light mode下是白色,在dark mode下是黑色

根据苹果的设计思路,适配darkmode就是通过UIKit提供的基础对象进行颜色和图片的控制 ,一些系统提供的控件已经适配了dark mode,但是还是有很多需要我们去适配的部分,开启我们的漫漫适配路吧~

如何切换mode

除了可以在setting->develop->Dark Appearance切换模式,Xcode 11增加了一个 辅助功能,可以帮助我们快速切换模拟器和storyboard或者xib的mode模式


切换模拟器的mode

切换storyboard的mode
Assets适配

颜色:创建一个颜色的Assets,调整Appearance为Any,Dark 然后就可以在里面配置不同Appearance的颜色啦~在assets添加自定义颜色是从iOS11开始的所以对老版本的iOS兼容不好 ,建议使用代码适配颜色

图片:assets的适配图片不会影响老的版本,老版本的iOS会自动识别 Any Appearance! 听到这里是不是超开心呢
代码适配
  • 系统的语义颜色以及系统颜色:这两种iOS13提供的动态颜色都会根据mode变化,帮助我们快速实现类似系统配色的适配,这里简单列举,大家感受一下~
    LabelColor :文本颜色
    secondaryLabelColor : 辅助内容的文本标签颜色
    tertiaryLabelColor :三级
    linkColor: 超链接标签颜色
    separatorColor/opaqueseparatorColor:分隔符(细边框或者分割线)
    systembackgroundColor :界面背景色
  • 创建Dynamic Color
UIColor *dyColor = [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull trainCollection) {
          if ([trainCollection userInterfaceStyle] == UIUserInterfaceStyleLight) {
              return lightColor;
              
          }else {
              return darkColor;
          }
      }];

关于图片的部分请继续往下看哦~

UITraitCollection

iOS trait环境简介
通过UITraitEnvironment协议的traitCollection属性公开。
UIScreen、UIWindow 、UIViewController、UIPresentationController、 UIView遵守了 UITraitEnvironment协议。
根据这些属性的变化自适应界面的布局、设置特殊属性:UITraitCollection(水平大小,垂直大小 展示的比列 用户界面习惯用法)
<UITraitCollection: 0x600003085800; UserInterfaceIdiom = Phone, DisplayScale = 3, DisplayGamut = P3, HorizontalSizeClass = Compact, VerticalSizeClass = Regular, UserInterfaceStyle = Dark, UserInterfaceLayoutDirection = 0, ForceTouchCapability = 2, PreferredContentSizeCategory = UICTContentSizeCategoryL, AccessibilityContrast = 1, UserInterfaceLevel = 1>

当我们设置颜色的时候发现是同样的systemBackgroundColor,但两边是不一样的颜色 原因是系统做了层级处理 ,这里的层级处理也是包含在UITraitCollection里面的UserInterfaceLevel,在显示颜色变化的基础上,做了一些透明度等其他的一些处理


其实dynamicColor就是通过trait获取可以获取当前的展示的具体是什么颜色

let dynamic color = UIColor.systemBackGround
let traitCollection = view. traitCollection
let resolvedColor = dynamicColor.resolvedColor(with: traitCollection)

重写drawRect方法的时候 ,UIkit会把当前的环境设置给view的traitCollection,这个时候用systemcolor绘制会使用正确的颜色,模式变化的时候会调用setNeedsDisplay触发drawRect方法

UIView、UIViewController、UIpresentationController对应的模式切换会调用的方法如下图所示,在下面方法处理的渲染是准确的

官方表示layout方法是我们使用traitcolletion的最好时机,把外观代码放到任何一个即可,不要做不必要的工作,可以调用他们的补充方法如 setNeedsUpdateConstraints、setNeedsLayout触发它们
但有些情况需特殊处理,比如CALayer 和 CGColor,他们不能识别darkMode, 我们需要通过traitcollection来处理
(1)通过CALayer添加上的view拿到它的traitcollection 获取当前需要展示的颜色 然后转成CGColor
(2)在performAsCurrent方法里面直接拿到当前的CGColor
(3)根据当前view的traitCollection判断,有时候view的traitCollection不一定和traitCollection.current保持一致,我们需要把当前的保存好赋值完成后设回去
知道mode的变化才能更好地控制我们需要改变的东西,mode变化会走的方法,横屏等操作也会走这个方法,建议先判断是否是颜色的变化

图片和颜色不一样的地方是图片没有颜色的动态处理mode,那么我们需要自己处理通过imageAsset来获取当前图片的具体展示

+(UIImage *)getdarkModeImage:(NSString *)imgName
             traitcollection:(UITraitCollection *)trait{
    if (@available(iOS 13.0, *)) {
        UIImage * imgs = [UIImage imageNamed:imgName inBundle:nil compatibleWithTraitCollection:[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleLight]];
        [imgs.imageAsset registerImage:[UIImage imageNamed:[NSString stringWithFormat:@"%@_dark",imgName]] withTraitCollection:[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleDark]];
        return [imgs.imageAsset imageWithTraitCollection:trait];
    }else{
        return [UIImage imageNamed:imgName];
    }
}

常规来看大家以为traitCollection是一个单利,大家根据他去做事情,但其实traitcollection贯穿了整个app,每个层级都有自己的raitcollection,每个层级根据自己的traitcollection做事情


当我们添加一个view的时候,它不知道怎么展示,addsubview的时候会将上一层的trait collection继承过来,就可以进行自己的mode的展示了

Xcode有一个的Debug 的功能 可以告诉我们谁的traitcollection变化了

假如我们想某个页面保持黑夜状态 那么我们可以在重写那个页面的traitcollection,那么它下面的页面也都是dark mode了

设置某个页面忽略系统模式

let darkView = UIView()
darkView.overrideUserInterfaceStyle = .dark(影响里面的层级结构)
viewWithCustomAppearance.overrideUserInterfaceStyle = .unspecified /设置回去

要使整个app一直保持黑色或者白色 在info.plist文件里面设置UIUserInterfaceStyle为light或者dark

高斯模糊效果的设置
UIBlurEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemThinMaterial];
        UIVisualEffectView *effectView = [[UIVisualEffectView alloc] initWithEffect:effect];
        //放大 UIVisualEffectView 视图下面的内容的颜色,同时让UIVisualEffectView视图的contentView看起来e更生动
        UIVibrancyEffect * vibrancyeffect = [UIVibrancyEffect effectForBlurEffect:effect style:UIVibrancyEffectStyleSecondaryLabel];
        UIVisualEffectView *vibrancyV = [[UIVisualEffectView alloc] initWithEffect:vibrancyeffect];
        [effectView.contentView addSubview:vibrancyV];
富文本

设置attributes的foregroundColor设置为.label,不指定则默认为.black

 NSMutableAttributedString *resultStr = [[NSMutableAttributedString alloc] initWithString: [NSString stringWithFormat: @"代金券(%@)",string]];
    [resultStr addAttribute:NSFontAttributeName value:BU_FONT_14 range:NSMakeRange(0, 3)];
    [resultStr addAttribute:NSForegroundColorAttributeName value:[UIColor generateDynamicColor:BU_COLOR_C1 darkColor:[UIColor whiteColor]] range:NSMakeRange(0,3)];//attribute的foregroundColor(VIP)
    
    [resultStr addAttribute:NSFontAttributeName value:BU_FONT_14 range:NSMakeRange(3, resultStr.length - 3)];
    [resultStr addAttribute:NSForegroundColorAttributeName value:BUColorWithHex(0xf81c46) range:NSMakeRange(3, resultStr.length - 3)];
    return resultStr;
iOS13新变化

StatusBar:之前分为default 和lightContent两种类型 ,现在darkcontent表示default样式下的light模式下的导航栏样式,现在default变成了dynamic类型,根据mode变化
UIActivityIndicatorView:去掉了之前的各种类型 ,现在是设置大小 ,颜色属性自己控制

webcontent

macOS 10.14.4中的Safari 12.1更新,WebKit中的暗模式支持已经到来。Safari和WebKit不会自动使网页内容变暗 ,内容支持暗模式的主要方式是采用color-scheme中指定的新样式属性。
查询通过CSS变量指定颜色值

:root {
    color-scheme: light dark;
    --special-text-color: hsla(60, 100%, 50%, 0.5);
    --border-color: black;
}

@media (prefers-color-scheme: dark) {
    :root {
        --special-text-color: hsla(60, 50%, 70%, 0.75);
        --border-color: white;
    }
}

.special {
    color: var(--special-text-color);
    border: 1px solid var(--border-color);
}

调整顺序建议 :xib -> storyboard->code ->富文本->画图方法,assets的图片只能用imageNamed的方式加载对内存不友好,但暗黑适配可以省去超多麻烦,同时assets的使用也有超多好处[ WWDC2018 ] - 优化 App Assets Optimizing App Assets 建议小的常用图片assets适配 ,大的或者网络图片代码适配 ,assets对颜色暗黑适配的iOS老版本不友好,最好还是代码适配

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容