iOS 13下暗黑(深色)模式的配置



暗黑模式在macOS上推出后,又推广到移动端——在iOS 13上正式开放出来!

其实简单而言就是以前常见App中的夜间模式罢了!只是集成到系统这个单例中去了而已!当然体验自我感觉不是很喜欢(不喜欢太暗色系的😂😂😂😂😂)


OK,进入主题!开始看看怎么配置iOS 13的暗黑模式!
在iOS 13(iPadOS 13同理)的设置中,叫"浅色"、"深色"!

外观:"浅色"、"深色"

对应的UIUserInterfaceStyle枚举:

typedef NS_ENUM(NSInteger, UIUserInterfaceStyle) {
    UIUserInterfaceStyleUnspecified,
    UIUserInterfaceStyleLight,
    UIUserInterfaceStyleDark,
} API_AVAILABLE(tvos(10.0)) API_AVAILABLE(ios(12.0)) API_UNAVAILABLE(watchos);


不适配暗黑模式

A.整个App都不使用,直接在项目的plist文件中设置——添加"User Interface Style"键,将值设为"UIUserInterfaceStyleLight":

在"Source Code"中的形式:

<key>UIUserInterfaceStyle</key> 
<string>UIUserInterfaceStyleLight</string>

B.各个UIViewController中不使用,设置 if (@available(iOS 13.0, *)){ self.overrideUserInterfaceStyle = UIUserInterfaceStyleLight; }

设置当前的ViewController为"深色"模式后,此ViewController下的所有view都是"深色"模式!
由此ViewController所present出来的ViewController是不会受到影响的,依然跟随系统的模式!



获取当前模式(浅色、深色)
if (UITraitCollection.currentTraitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) { //当前 "深色"模式
    
} else { //当前 "浅色"模式
    
}



颜色(UIColor)的处理:

A.系统自带的视图设置相应的配色:

从 iOS 13开始UIColor是一个动态颜色,在"浅色"和"深色"模式下可以分别展示出不同的颜色!以下是iOS 13系统所提供的动态颜色:

@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

对于ViewController:

[self.view setBackgroundColor:[UIColor systemBackgroundColor]];

对于UITableviewCell:

[self.titleLabel setTextColor:[UIColor labelColor]];
[self.detailLabel setTextColor:[UIColor placeholderTextColor]];


B.自定义的视图设置相应的配色:自定义动态颜色

+ (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);
使用方式如下:
self.bgView.backgroundColor = [UIColor whiteColor];

在需要处理暗黑模式的地方,再添加上如下代码:(设置相应配色)

if (@available(iOS 13.0, *)) {
    UIColor * rightColor = [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull trainCollection) {
        if ([trainCollection userInterfaceStyle] == UIUserInterfaceStyleLight) { //浅色模式
            return [UIColor whiteColor];
        } else { //深色模式
            return [UIColor blackColor];
        }
    }];
    self.bgView.backgroundColor = rightColor; //根据当前模式(光明\暗黑)-展示相应颜色
}



图片的处理

在Xcode 11中,为".xcassets"文件带来了更新以自动读取加载"浅色"/"深色"模式的资源(其中的图片)!

修改资源的Appearances属性,来设置是否要支持"浅色"/"深色"模式及相应的资源内容("浅色"图片/"深色"图片)!在调用“[UIImage imageNamed:@"图片名"]”方法时,会自动加载相应的"浅色"/"深色"资源("浅色"图片/"深色"图片)。

图片资源的Appearances属性有三个选项:"None"、"Any,Dark""Any,Light,Dark"
选第二项就够用了("默认"/"深色"模式)!要选第三项进行配置也行("默认"/"浅色"/"深色"模式)!

选择第二项("默认"/"深色"模式)

"浅色"/"深色"模式的效果:
"浅色"/"深色"模式下的效果



模式切换的监听

在需要监听的viewController中,重写如下方法(得到切换前模式):

-(void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
    [super traitCollectionDidChange:previousTraitCollection];
    
    //previousTraitCollection:之前的模式("浅色"/"深色")
    if (@available(iOS 13.0, *)) {
        switch (previousTraitCollection.userInterfaceStyle) { //之前的模式("浅色"/"深色")
            case UIUserInterfaceStyleUnspecified:{ // 0
                NSLog(@"previousTraitCollection: UIUserInterfaceStyleUnspecified");
            } break;
            case UIUserInterfaceStyleLight:{
                NSLog(@"previousTraitCollection: UIUserInterfaceStyleLight");
            } break;
            case UIUserInterfaceStyleDark:{
                NSLog(@"previousTraitCollection: UIUserInterfaceStyleDark");
            } break;
            default:
                break;
        }

        if (UITraitCollection.currentTraitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) { //当前 "深色"模式
          NSLog(@"now  changedTo TraitCollection: UIUserInterfaceStyleDark");
        } else { //当前 "浅色"模式
          NSLog(@"now  changedTo TraitCollection: UIUserInterfaceStyleLight");
        }
        
        
        //⭐️进行相应的  界面UI调整⭐️
        
    }
}

“判断两个UITraitCollection对象是否不同”的方法:

- (BOOL)hasDifferentColorAppearanceComparedToTraitCollection:(UITraitCollection *)traitCollection;



实时观察当前模式(其他方法)

根据实时返回的trainCollection进行监听方法调用[weakSelf performSelector:@selector(traitCollectionChanged:) withObject:trainCollection];
以“+ (UIColor *)colorWithDynamicProvider:(UIColor * (^)(UITraitCollection *traitCollection))dynamicProvider”方法为跳板!


 UIColor * rightColor = [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull trainCollection) {
       [weakSelf performSelector:@selector(traitCollectionChanged:) withObject:trainCollection];
       if ([trainCollection userInterfaceStyle] == UIUserInterfaceStyleLight) {
           return [UIColor whiteColor];
       } else {
           return [UIColor blackColor];
       }
   }];


对“-(void)traitCollectionChanged:(UITraitCollection *)traitCollection”方法的调用:

-(void)traitCollectionChanged:(UITraitCollection *)traitCollection{
    if (@available(iOS 13.0, *)) {
        switch (traitCollection.userInterfaceStyle) {
            case UIUserInterfaceStyleUnspecified:{
                NSLog(@"Now traitCollection: UIUserInterfaceStyleUnspecified");
            } break;
            case UIUserInterfaceStyleLight:{
                NSLog(@"Now traitCollection: UIUserInterfaceStyleLight");
            } break;
            case UIUserInterfaceStyleDark:{
                NSLog(@"Now traitCollection: UIUserInterfaceStyleDark");
            } break;
            default:
                break;
        }
        
        
        //⭐️进行相应的  界面UI调整⭐️
        
    }
}







已经记不到上次写文章是好久了😂😂😂😂😂
难的闲下来一次。。。





goyohol's essay