Adapt JDME To iOS13 DarkMode

784 阅读4分钟

全局关闭DarkMode

这是目前采取的方案,让APP始终保持LightMode,在info.plsit文件中,添加UIUserInterfaceStyle , 值为Light

我们要适配DarkMode,需要将UIUserInterfaceStyle删除。

UIColor

iOS13之前 UIColor只能表示一种颜色,从iOS13开始UIColor是一个动态的颜色,在LightModeDarkMode可以分别设置不同的颜色。

1.首先系统为我们提供了一些动态颜色,使用这种动态颜色,系统直接替我们完成了适配工作。但是系统提供的颜色不符合APP的设计规范的话,一般情况下我们用不到。
@property (class, nonatomic, readonly) UIColor *systemBrownColor        API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
@property (class, nonatomic, readonly) UIColor *systemIndigoColor       API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
@property (class, nonatomic, readonly) UIColor *systemGray2Color        API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
...
...
2.自定义动态UIColor
UIColor *textDyColor = [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull traitCollection) {
      if (traitCollection.userInterfaceStyle == UIUserInterfaceStyleLight) {
          return [UIColor JMEColorWithHexString:@"#2E2D2D"];
      } else {
          return [UIColor yellowColor];
      }
 }];
 _nameLabel.textColor = textDyColor;

这样当系统切换DarkMode/LightMode时,会回调(UIColor * (^)(UITraitCollection *traitCollection))dynamicProvider这个block,自动为我们更新颜色。

图片资源

JDME目前使用了Assets.xcassets来管理图片,适配DarkMode还是比较方便的。

打开Assets.xcassets,设置AppearanceAny,Dark

将设计师提供的DarkMode素材图片拖入对应的位置,还像往常一样使用图片就可以了。

[_logoImage setImage:[UIImage imageNamed:@"icon_logo"]];

获取当前模式(LightMode/DarkMode)

上面提到的颜色和图片,都是由系统来帮我们完成切换的。但是在某些场景下,我们需要根据当前的模式,来做一些其他的适配需求。

我们可以在 UIViewController 或者 UIView 中调用traitCollection.userInterfaceStyle来获取当前视图的模式。

    
    if (@available(iOS 13.0, *)) {
        UIUserInterfaceStyle style = self.traitCollection.userInterfaceStyle;
        if (style == UIUserInterfaceStyleLight) {
            ///TODO:...
        } else {
            ///TODO:...
        }
    }
    

userInterfaceStyleiOS12出现的,但是暗黑模式是iOS13才有的,所以为了避免不必要的影响,我们还是加上@available(iOS 13.0, *) 的判断条件。

适当的时候我们可能还需要在drawRect/layoutSubViews等方法中,根据当前的模式重新设定一些色值。

监听模式的切换(LightMode/DarkMode)

无论是LightMode还是DarkMode,用户都可以切出APP,或者下拉控制中心浮层来随意切换,所以我们还需要监听模式的切换。

UIViewUIViewController 中,当模式切换时,就会触发下面这个方法

- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
    if (@available(iOS 13.0, *)) {
        if ([self.traitCollection hasDifferentColorAppearanceComparedToTraitCollection:previousTraitCollection]) {
            ///TODO:...
        }
    } else {
        // Fallback on earlier versions
    }
}

CGColor

对于CGColor,我们可以使用上述的获取当前模式和监听模式的方式来处理不同的CGColor

Status Bar

之前 Status Bar 有两种状态,defaultlightContent

现在 Status Bar 有三种状态,default, darkContentlightContent

现在的 darkContent 对应之前的 default,现在的 default 会根据情况自动选择 darkContentlightContent

JDME中设置状态栏颜色的地方有很多,这个还得具体情况具体分析。

UIActivityIndicatorView

之前的 UIActivityIndicatorView 有三种 style 分别为 whiteLarge, whitegray现在全部废弃

增加两种 style 分别为 mediumlarge,指示器颜色用 color 属性修改。

NSAttributedString

对于UILabelUITextFieldUITextView,在设置NSAttributedString时也要考虑适配Dark Mode

Storyboard/Xib

xib中,系统提供了使用colorAssets的方式,类似于图片,但是为了兼容低版本,我们还是需要手动代码来更改颜色,单独适配。

第三方模块:

H5 App (WKWebview)

具体由第三方应用做适配

SDK

需要相关团队做适配。

Flutter Module (Calendar/Login)

尽管 FlutterMaterialApp中提供了themedarkTheme两个入口让我们设置两种模式下的颜色及文字样式,但是还是需要注意一些细节,提供的样式是否与设计师的要求一致。

注意,Flutter 1.9.1的版本并没有适配iOS 13 Status Bar新增的UIStatusBarStyleDarkContent

ReactNative Module (JoySpace)

RN团队需要做适配。

对于设计师

设计师需要提供一套设计规范,作为底层颜色自动转换的映射表。我们使用系统提供的方案,可以很快做到颜色转换来适配暗黑色模式。但是,有些颜色是需要单独配置的,不能完全遵循底层的颜色转换,所以,每个页面都需要设计人员验收,自动转换的颜色是否符合整体页面的UI效果,如果有变动,尽量给出一份暗黑模式的标注图,然后我们再做单独配置。所以,对于设计人员和开发需要适配的工作量还是蛮大的。