扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
好像大概也许是一年前, Mac OS系统发布了深色模式外观, 看着挺刺激, 时至今日用着也还挺爽的
站在用户的角度思考问题,与客户深入沟通,找到三水网站设计与三水网站推广的解决方案,凭借多年的经验,让设计与互联网技术结合,创造个性化、用户体验好的作品,建站类型包括:成都做网站、网站制作、企业官网、英文网站、手机端网站、网站推广、国际域名空间、虚拟主机、企业邮箱。业务覆盖三水地区。
终于, 随着iPhone11等新手机的发售, iOS 13系统也正式发布了, 伴随着手机版的深色模式也出现在了大众视野
我们这些iOS程序猿也有事情做了, 原有项目适配iOS13系统, 适配Dark Mode深色模式
虽然现在并没有要求强制适配Dark Mode, 但是DarK适配却也迫在眉睫
Apps on iOS 13 are expected to support dark mode Use system colors and materials Create your own dynamic colors and images Leverage flexible infrastructure
获取当前模式
提供两种方式设置手机当前外观模式
获取当前模式
我们需要选获取到当前出于什么模式, 在根据不同的模式进行适配, iOS 13中新增了获取当前模式的API
Swift
// 获取当前模式 let currentMode = UITraitCollection.current.userInterfaceStyle if (currentMode == .dark) { print("深色模式") } else if (currentMode == .light) { print("浅色模式") } else { print("未知模式") } open var userInterfaceStyle: UIUserInterfaceStyle { get } // 所有模式 public enum UIUserInterfaceStyle : Int { // 未指明的 case unspecified // 浅色模式 case light // 深色模式 case dark }
OC语言
if (@available(iOS 13.0, *)) { UIUserInterfaceStyle mode = UITraitCollection.currentTraitCollection.userInterfaceStyle; if (mode == UIUserInterfaceStyleDark) { NSLog(@"深色模式"); } else if (mode == UIUserInterfaceStyleLight) { NSLog(@"浅色模式"); } else { NSLog(@"未知模式"); } } // 各种枚举值 typedef NS_ENUM(NSInteger, UIUserInterfaceStyle) { UIUserInterfaceStyleUnspecified, UIUserInterfaceStyleLight, UIUserInterfaceStyleDark, } API_AVAILABLE(tvos(10.0)) API_AVAILABLE(ios(12.0)) API_UNAVAILABLE(watchos);
监听系统模式的变化
在iOS13系统中, UIViewController遵循了两个协议: UITraitEnvironment
和UIContentContainer
协议
在UITraitEnvironment
协议中, 为我们提供了一个监听当前模式变化的方法
@protocol UITraitEnvironment// 当前模式 @property (nonatomic, readonly) UITraitCollection *traitCollection API_AVAILABLE(ios(8.0)); // 重写该方法监听模式的改变 - (void)traitCollectionDidChange:(nullable UITraitCollection *)previousTraitCollection API_AVAILABLE(ios(8.0)); @end
public protocol UITraitEnvironment : NSObjectProtocol { // 当前模式 @available(iOS 8.0, *) var traitCollection: UITraitCollection { get } // 重写该方法监听模式的改变 @available(iOS 8.0, *) func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) } // 使用方法 override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) // 每次模式改变的时候, 这里都会执行 print("模式改变了") }
颜色相关适配
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); @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)
在OC中
+ (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);
fileprivate func getColor() -> UIColor { return UIColor { (collection) -> UIColor in if (collection.userInterfaceStyle == .dark) { return UIColor.red } return UIColor.green } }
除了上述两个方法之外, UIColor还增加了一个实例方法
// 通过当前traitCollection得到对应UIColor @available(iOS 13.0, *) open func resolvedColor(with traitCollection: UITraitCollection) -> UIColor
CGColor
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) // 每次模式改变的时候, 这里都会执行 if (previousTraitCollection?.userInterfaceStyle == .dark) { redView.layer.borderColor = UIColor.red.cgColor } else { redView.layer.borderColor = UIColor.green.cgColor } }
图片适配
在iOS中, 图片基本都是放在Assets.xcassets里面, 所以图片的适配, 我们就相对麻烦一些了
正常情况下都是下面这中处理方式
需要适配不同模式的情况下, 需要两套不同的图片, 并做如下设置
在设置Appearances时, 我们选择Any, 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?) { super.traitCollectionDidChange(previousTraitCollection) // 每次模式改变的时候, 这里都会执行 if (previousTraitCollection?.userInterfaceStyle == .dark) { // 在Dark模式下, 强制改成Light模式 overrideUserInterfaceStyle = .light } }
强制项目的显示模式
上面这种方式只能针对某一个页面修改, 如果需要对整个项目禁用Dark模式
可以通过修改window的overrideUserInterfaceStyle属性
在Xcode11创建的项目中, window从AppDelegate移到SceneDelegate中, 添加下面这段代码, 就会做到全局修改显示模式
let scene = UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate scene?.window?.overrideUserInterfaceStyle = .light
在之前的项目中, 可以在AppDelegate设置如下代码
window.overrideUserInterfaceStyle = .light
我创建的简单项目, 上述代码的确会强制改变当前的模式, 但是状态栏的显示不会被修改, 不知道是不是漏了什么
终极方案
需要在info.plist文件中添加User Interface Style配置, 并设置为Light
UIUserInterfaceStyle Light
问题又来了, 即使做了上面的修改, 在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的代码中, 设置状态栏的颜色为黑色, 代码如下
上面这段代码在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 其他更新
苹果登录
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提供的按钮样式,已经适配各类设备, 可参考Sign In with Apple
LaunchImage
即将被废弃的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 { }
到此这篇关于iOS13适配深色模式(Dark Mode)的实现的文章就介绍到这了,更多相关iOS13适配深色模式内容请搜索创新互联以前的文章或继续浏览下面的相关文章希望大家以后多多支持创新互联!
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流