iOS13深⾊模式与浅⾊模式适配讲解
iOS 13
2019年6⽉4⽇凌晨,苹果在开发者⼤会上推出了新⼀代⼿机操作系统iOS 13,主要更新了照⽚应⽤、滑动输⼊和更多动画表情,还有就是增加了”深⾊模式“,优化了⾳量的调节⽅式。
深⾊模式”终于来了“。
在所有关于iOS13的更新项⽬⾥,“深⾊模式”是⽹友讨论最多的。该模式可以根据⽇出⽇落时间⾃动开启,开启后,不只有壁纸,所有的系统元素都会变成暗⾊,起到在夜⾥降低屏幕亮度、保护⽤户眼睛的作⽤。
Light Mode and Dark Mode
实际上,苹果⽤户很早就开始呼吁iOS加⼊这个深⾊模式。如今iOS13正式发布深⾊模式,媒体和⽹友评论的⼝吻都是“终于来了”,“迟到的深⾊模式”。
Dark Mode Apps
对于iOS程序猿们⽽⾔,如何适配iOS13系统的深⾊模式呢?我推荐从以下⼏个⽅⾯去做适配,推荐参考项⽬。
运⽤系统 API
如何运⽤系统API,请阅读这篇⽂章。
颜⾊相关的适配
不同模式的适配主要涉及颜⾊和图⽚两个⽅⾯的适配。
其中颜⾊适配,包括相关背景⾊和字体颜⾊。
当系统模式切换的时候,我们不需要如何操作,系统会⾃动渲染页⾯,只需要做好不同模式的颜⾊和图⽚即可。
UIColor
iOS13之前UIColor只能表⽰⼀种颜⾊,从iOS13开始UIColor是⼀个动态的颜⾊,在不同模式下可以分别代表不同的颜⾊。
下⾯是iOS13系统提供的动态颜⾊种类,使⽤以下颜⾊值,在模式切换时,则不需要做特殊处理。
@interface UIColor (UIColorSystemColors)
#pragma mark System colors
@property (class, nonatomic, readonly) UIColor *systemRedColor          API_AVAILABLE(ios(7.0), tvos(9.0)) API_UNAVAILABLE(watchos);
@property (class, nonatomic, readonly) UIColor *systemGreenColor        API_AVAILABLE(ios(7.0), tvos(9.0)) API_UNAVAILABLE(watchos);
@property (class, nonatomic, readonly) UIColor *systemBlueColor        API_AVAILABLE(ios(7.0), tvos(9.0)) API_UNAVAILABLE(watchos);
@property (class, nonatomic, readonly) UIColor *systemOrangeColor      API_AVAILABLE(ios(7.0), tvos(9.0)) API_UNAVAILABLE(watchos);
@property (class, nonatomic, readonly) UIColor *systemYellowColor      API_AVAILABLE(ios(7.0), tvos(9.0)) API_UNAVAILABLE(watchos);
app开发者需要更新此app以在此ios上正常使用@property (class, nonatomic, readonly) UIColor *systemPinkColor        API_AVAILABLE(ios(7.0), tvos(9.0)) API_UNAVAILABLE(watchos);
@property (class, nonatomic, readonly) UIColor *systemPurpleColor      API_AVAILABLE(ios(9.0), tvos(9.0)) API_UNAVAILABLE(watchos);
@property (class, nonatomic, readonly) UIColor *systemTealColor        API_AVAILABLE(ios(7.0), tvos(9.0)) API_UNAVAILABLE(watchos);
@property (class, nonatomic, readonly) UIColor *systemIndigoColor      API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
// 灰⾊种类, 在Light模式下, systemGray6Color更趋向于⽩⾊
@property (class, nonatomic, readonly) UIColor *systemGrayColor        API_AVAILABLE(ios(7.0), tvos(9.0)) API_UNAVAILABLE(watchos);
@property (class, nonatomic, readonly) UIColor *systemGray2Color        API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
@property (class, nonatomic, readonly) UIColor *systemGray3Color        API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
@property (class, nonatomic, readonly) UIColor *systemGray4Color        API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
@property (class, nonatomic, readonly) UIColor *systemGray5Color        API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
@property (class, nonatomic, readonly) UIColor *systemGray6Color        API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
#pragma mark Foreground colors
@property (class, nonatomic, readonly) UIColor *labelColor              API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
@property (class, nonatomic, readonly) UIColor *secondaryLabelColor    API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
@property (class, nonatomic, readonly) UIColor *tertiaryLabelColor      API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
@property (class, nonatomic, readonly) UIColor *quaternaryLabelColor    API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
// 系统链接的前景⾊
@property (class, nonatomic, readonly) UIColor *linkColor              API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
// 占位⽂字的颜⾊
@property (class, nonatomic, readonly) UIColor *placeholderTextColor    API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
// 边框或者分割线的颜⾊
@property (class, nonatomic, readonly) UIColor *separatorColor          API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
@property (class, nonatomic, readonly) UIColor *opaqueSeparatorColor    API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
#pragma mark Background colors
@property (class, nonatomic, readonly) UIColor *systemBackgroundColor                  API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
@property (class, nonatomic, readonly) UIColor *secondarySystemBackgroundColor          API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
@property (class, nonatomic, readonly) UIColor *tertiarySystemBackgroundColor          API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
@property (class, nonatomic, readonly) UIColor *systemGroupedBackgroundColor            API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
@property (class, nonatomic, readonly) UIColor *secondarySystemGroupedBackgroundColor  API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
@property (class, nonatomic, readonly) UIColor *tertiarySystemGroupedBackgroundColor    API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
#pragma mark Fill colors
@property (class, nonatomic, readonly) UIColor *systemFillColor                        API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
@property (class, nonatomic, readonly) UIColor *secondarySystemFillColor                API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
@property (class, nonatomic, readonly) UIColor *tertiarySystemFillColor                API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
@property (class, nonatomic, readonly) UIColor *quaternarySystemFillColor              API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
#pragma mark Other colors
// 这两个是⾮动态颜⾊值
@property(class, nonatomic, readonly) UIColor *lightTextColor API_UNAVAILABLE(tvos);    // for a dark background
@property(class, nonatomic, readonly) UIColor *darkTextColor API_UNAVAILABLE(tvos);    // for a light background
@property(class, nonatomic, readonly) UIColor *groupTableViewBackgroundColor API_DEPRECATED_WITH_REPLACEMENT("systemGroupedBackgroundColor", ios(2.0, 13.0), tvos(13.0, 13.0)); @property(class, nonatomic, readonly) UIColor *viewFlipsideBackgroundColor API_DEPRECATED("", ios(2.0, 7.0)) API_UNAVAILABLE(tvos);
@property(class, nonatomic, readonly) UIColor *scrollViewTexturedBackgroundColor API_DEPRECATED("", ios(3.2, 7.0)) API_UNAVAILABLE(tvos);
@property(class, nonatomic, readonly) UIColor *underPageBackgroundColor API_DEPRECATED("", ios(5.0, 7.0)) API_UNAVAILABLE(tvos);
@end
上⾯系统提供的这些颜⾊种类,根本不能满⾜我们正常开发的需要,⼤部分的颜⾊值也都是⾃定义。
系统也为我们提供了创建⾃定义颜⾊的⽅法。
@available(iOS 13.0, *)
public init(dynamicProvider: @escaping (UITraitCollection) -> UIColor)
在Objective-C中
+ (UIColor *)colorWithDynamicProvider:(UIColor * (^)(UITraitCollection *traitCollection))dynamicProvider API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
- (UIColor *)initWithDynamicProvider:(UIColor * (^)(UITraitCollection *traitCollection))dynamicProvider API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
上⾯的⽅法接受⼀个闭包 (block) 。
当系统在LightMode和DarkMode之间相互切换时就会⾃动触发此回调。
回调返回⼀个UITraitCollection,可根据改对象判断是那种模式。
fileprivate func getColor() -> UIColor {
return UIColor { (collection) -> UIColor in
if (collection.userInterfaceStyle == .dark) {
d
}
}
}
除了上述两个⽅法之外,UIColor还增加了⼀个实例⽅法。
// 通过当前 traitCollection 得到对应 UIColor
@available(iOS 13.0, *)
open func resolvedColor(with traitCollection: UITraitCollection) -> UIColor
CGColor
UIColor只是设置背景⾊和⽂字颜⾊的类,可以动态的设置。
可是如果是需要设置类似边框颜⾊等属性时,⼜该如何处理呢?
设置上述边框属性,需要⽤到CGColor类,但是在iOS13中CGColor并不是动态颜⾊值,只能表⽰⼀种颜⾊。
在监听模式改变的⽅法中traitCollectionDidChange,根据不同的模式进⾏处理。
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
// 每次模式改变的时候, 这⾥都会执⾏
if (previousTraitCollection?.userInterfaceStyle == .dark) {
redView.layer.borderColor = Color
} else {
redView.layer.borderColor = Color
}
}
图⽚适配
在iOS中,图⽚基本都是放在assets⾥⾯,所以图⽚的适配,我们就相对⿇烦⼀些了。
正常情况下都是下⾯这中处理⽅式。
Appearances None
需要适配不同模式的情况下,需要两套不同的图⽚,并做如下设置。
在设置Appearances时,我们选择Any, Dark就可以了 (只需要适配深⾊模式和⾮深⾊模式)。
Appearances Dark
适配相关
当前页⾯模式
原项⽬中如果没有适配Dark Mode,当你切换到Dark Mode后,你可能会发现有些部分页⾯的颜⾊⾃动适配了。
未设置过背景颜⾊或者⽂字颜⾊的组件,在Dark Mode模式下,就是⿊⾊的。
这⾥我们就需要真对该单独App强制设置成Light Mode模式。
// 设置改属性, 只会影响当前的视图, 不会影响前⾯的 controller 和后续 present 的 controller
@available(iOS 13.0, *)
open var overrideUserInterfaceStyle: UIUserInterfaceStyle
// 使⽤⽰例
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
// 每次模式改变的时候, 这⾥都会执⾏
if (previousTraitCollection?.userInterfaceStyle == .dark) {
// 在Dark模式下, 强制改成Light模式
overrideUserInterfaceStyle = .light
}
}
强制项⽬的显⽰模式
上⾯这种⽅式只能针对某⼀个页⾯修改,如果需要对整个项⽬禁⽤Dark模式。
可以通过修改window的overrideUserInterfaceStyle属性。
在Xcode11创建的项⽬中,window从AppDelegate移到SceneDelegate中,添加下⾯这段代码,就会做到全局修改显⽰模式。
let scene = tedScenes.first?.delegate as? SceneDelegate
scene?.window?.overrideUserInterfaceStyle = .light
在之前的项⽬中,可以在AppDelegate设置如下代码:
window.overrideUserInterfaceStyle = .light
我创建的项⽬,上述代码的确会强制改变当前的模式,但是状态栏的显⽰不会被修改。
终极⽅案
需要在info.plist⽂件中添加User Interface Style配置,并设置为Light。
<key>UIUserInterfaceStyle</key>
<string>Light</string>
问题⼜来了,即使做了上⾯的修改,在React Native中,状态栏的依然是根据不同的模式显⽰不同的颜⾊,该如何处理?Status Bar 更新
在iOS13中苹果对于Status Bar也做了部分修改,在iOS13之前
public enum UIStatusBarStyle : Int {
case `default` // 默认⽂字⿊⾊
@available(iOS 7.0, *)
case lightContent // ⽂字⽩⾊
}
从iOS13开始UIStatusBarStyle⼀共有三种状态
public enum UIStatusBarStyle : Int {
case `default` // ⾃动选择⿊⾊或⽩⾊
@available(iOS 7.0, *)
case lightContent // ⽂字⽩⾊
@available(iOS 13.0, *)
case darkContent // ⽂字⿊⾊
}
在React Native的代码中,设置状态栏的颜⾊为⿊⾊,代码如下:
<StatusBar barStyle={'dark-content'} />
上⾯这段代码在iOS13系统的⼿机中是⽆效的。
虽然上⾯的代码中设置了dark-content模式,但是在iOS原⽣代码中dark-content实际是 `UIStatusBarStyleDefault。
在⽂件RCTStatusBarManager.m中
RCT_ENUM_CONVERTER(UIStatusBarStyle, (@{
@"default": @(UIStatusBarStyleDefault),
@"light-content": @(UIStatusBarStyleLightContent),
@"dark-content": @(UIStatusBarStyleDefault),
}), UIStatusBarStyleDefault, integerValue);
修改上⾯代码即可
@"dark-content": @(@available(iOS 13.0, *) ? UIStatusBarStyleDarkContent : UIStatusBarStyleDefault),
iOS13 其他更新
Apple 登录
Sign In with Apple will be available for beta testing this summer. It will be required as an option for users in apps that support third-party sign-in when it is commercially available later this year.
如果APP⽀持三⽅登陆 (Facbook、Google、、QQ、⽀付宝等),就必须⽀持Apple登陆,且要放置前边。
⾄于Apple登录按钮的样式,建议⽀持使⽤Apple提供的按钮样式,已经适配各类设备,可参考。
LaunchImage
即将被废弃的LaunchImage。
从iOS 8的时候,苹果就引⼊了LaunchScreen,我们可以设置LaunchScreen来作为启动页。
现在你还可以使⽤LaunchImage来设置启动图,但是随着苹果设备尺⼨越来越多,适配显然相对⿇烦⼀些。
使⽤LaunchScreen的话,情况会变的很简单,LaunchScreen是⽀持AutoLayout和SizeClass的,所以适配各种屏幕都不在话下。
⚠ 从2020年4⽉开始,所有App将必须提供LaunchScreen,⽽LaunchImage即将退出历史舞台。
UIWebView
'UIWebView' was deprecated in iOS 12.0: No longer supported; please adopt WKWebView.
从iOS 13开始也不再⽀持UIWebView控件了,请尽快采⽤WKWebView。
@available(iOS, introduced: 2.0, deprecated: 12.0, message: "No longer supported; please adopt WKWebView.")
open class UIWebView : UIView, NSCoding, UIScrollViewDelegate { }

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。