iOS开发暗黑模式适配

释放双眼,带上耳机,听听看~!

根据苹果的⼀贯保持的⻛格,我们会特别简单、舒服的适配了它。 因此,苹果介绍的就是这三句句话。
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老版本不友好,最好还是代码适配

 

人已赞赏
iOS文章

iOS开发应用砸壳

2021-2-4 16:54:52

iOS文章

iOS开发停止NSTimer循环引用的五种方法

2021-2-4 19:24:52

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索