iOS13 黑暗模式的兼容
苹果在iOS 13中推出了黑暗模式的主题,这个主题切换过来使用时会让用户产生一种沉浸式的体验感受,最主要的是,它还能省电,不得不说苹果为了这个的确是煞费苦心,众所周知苹果的旗舰机主打的屏幕都是OLED(LCD的用户就当没看见这个就好了),而OLED有个特点就是点发光二极管,它可以不发光来显示黑色,这就是它省电的原因了。
但是它并不完全是系统自适配,还需要开发者去适配才行。
那么我们应该怎么去适配呢?
图片适配
首先是Assets.xcassets 的适配,一般而言,我们都会把开发中APP所需要使用到的图片都存放在这里面,我们可以先看看没有适配时的文件架构是下面这样的:
image-20191022150142623.png如果我们需要通过图片来适配不同的主题模式,需要进行不同的图片配置,像下面那样:
image-20191022150506445.png代码颜色适配
那么我们如何在代码中进行颜色的适配呢?
颜色的适配主要是靠UIColor类,我们进入到他的类里面,可以看到关于iOS 13所新增的接口:
/* Create a dynamic color with a provider.
* When methods are called on this color that need color component values,
* the provider is called with UITraitCollection.currentTraitCollection.
* The provider should use that trait collection to decide a more fundamental UIColor to return.
* As much as possible, use the given trait collection to make that decision, not other state.
*/
+ (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);
for example:
[UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull traitCollection) {
if (traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {
return [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0];
}else{
return [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:1.0];
}
}];
在iOS 13中,UIColor不再只表示一种颜色,它变成了一个动态的颜色,根据LightMode和DarkMode分别返回不同的颜色。
iOS 13中提供了一些动态颜色如下:
// System colors
@interface UIColor (UIColorSystemColors)
#pragma mark System colors
/* Some colors that are used by system elements and applications.
* These return named colors whose values may vary between different contexts and releases.
* Do not make assumptions about the color spaces or actual colors used.
*/
@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);
/* Shades of gray. systemGray is the base gray color.
*/
@property (class, nonatomic, readonly) UIColor *systemGrayColor API_AVAILABLE(ios(7.0), tvos(9.0)) API_UNAVAILABLE(watchos);
/* The numbered variations, systemGray2 through systemGray6, are grays which increasingly
* trend away from systemGray and in the direction of systemBackgroundColor.
*
* In UIUserInterfaceStyleLight: systemGray1 is slightly lighter than systemGray.
* systemGray2 is lighter than that, and so on.
* In UIUserInterfaceStyleDark: systemGray1 is slightly darker than systemGray.
* systemGray2 is darker than that, and so on.
*/
@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
/* Foreground colors for static text and related elements.
*/
@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);
/* Foreground color for standard system links.
*/
@property (class, nonatomic, readonly) UIColor *linkColor API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
/* Foreground color for placeholder text in controls or text fields or text views.
*/
@property (class, nonatomic, readonly) UIColor *placeholderTextColor API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
/* Foreground colors for separators (thin border or divider lines).
* `separatorColor` may be partially transparent, so it can go on top of any content.
* `opaqueSeparatorColor` is intended to look similar, but is guaranteed to be opaque, so it will
* completely cover anything behind it. Depending on the situation, you may need one or the other.
*/
@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
/* We provide two design systems (also known as "stacks") for structuring an iOS app's backgrounds.
*
* Each stack has three "levels" of background colors. The first color is intended to be the
* main background, farthest back. Secondary and tertiary colors are layered on top
* of the main background, when appropriate.
*
* Inside of a discrete piece of UI, choose a stack, then use colors from that stack.
* We do not recommend mixing and matching background colors between stacks.
* The foreground colors above are designed to work in both stacks.
*
* 1. systemBackground
* Use this stack for views with standard table views, and designs which have a white
* primary background in light mode.
*/
@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);
/* 2. systemGroupedBackground
* Use this stack for views with grouped content, such as grouped tables and
* platter-based designs. These are like grouped table views, but you may use these
* colors in places where a table view wouldn't make sense.
*/
@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
/* Fill colors for UI elements.
* These are meant to be used over the background colors, since their alpha component is less than 1.
*
* systemFillColor is appropriate for filling thin and small shapes.
* Example: The track of a slider.
*/
@property (class, nonatomic, readonly) UIColor *systemFillColor API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
/* secondarySystemFillColor is appropriate for filling medium-size shapes.
* Example: The background of a switch.
*/
@property (class, nonatomic, readonly) UIColor *secondarySystemFillColor API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
/* tertiarySystemFillColor is appropriate for filling large shapes.
* Examples: Input fields, search bars, buttons.
*/
@property (class, nonatomic, readonly) UIColor *tertiarySystemFillColor API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
/* quaternarySystemFillColor is appropriate for filling large areas containing complex content.
* Example: Expanded table cells.
*/
@property (class, nonatomic, readonly) UIColor *quaternarySystemFillColor API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
#pragma mark Other colors
/* lightTextColor is always light, and darkTextColor is always dark, regardless of the current UIUserInterfaceStyle.
* When possible, we recommend using `labelColor` and its variants, instead.
*/
@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
/* groupTableViewBackgroundColor is now the same as systemGroupedBackgroundColor.
*/
@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
当然,这里只表示了一部分的颜色,更多的其他颜色还是需要我们自己通过代码来适配
UIColor *btColor = [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull traitCollection) {
if (traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {
return [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0];
}else{
return [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:1.0];
}
}];
self.view.backgroundColor = btColor;
当我们在软件运行被切换成了黑暗模式的话则需要在各个页面内进行对应的变换。
相应的,在使用UIViewController以及UIView一些相关的控件时,就会涉及到一些重绘的方法诸如以下:
UIViewController
-(void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection{
}
-(void)viewWillLayoutSubviews{
}
-(void)viewDidLayoutSubviews{
}
-(void)updateViewConstraints{
}
UIView
-(void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection{
}
-(void)drawRect:(CGRect)rect{
}
-(void)layoutSubviews{
}
-(void)updateConstraints{
}
-(void)tintColorDidChange{
}
黑暗模式我们也可以不支持
只需要在Info.plist里面添加对应的字段:UIUserInterfaceStyle 然后把它的值设为Light就可以了,这个是全局设置成不支持黑暗模式的。不过以苹果以往的尿性,肯定会搞个不支持黑暗模式就不让你审核通过的政策的。
但是也可以在单个界面中指定不遵循黑暗模式
UIViewController 和 UIView 都新增了一个属性:overrideUserInterfaceStyle
Like this:
-(UIUserInterfaceStyle)overrideUserInterfaceStyle{
return UIUserInterfaceStyleLight;
}