iOS夜間模式開發(fā)探索(iOS13)

1、背景

1.1 iOS13蘋果推出了dark mode模式,很多系統(tǒng)內(nèi)置應(yīng)用都支持了dark mode模式,大家可以安裝一下beta版本看一下,就連地圖應(yīng)用都支持了dark mode模式、大部分我們自己開發(fā)app如果使用地圖的話基本上都是使用第三方的sdk,比如百度地圖,高德地圖,如果三方地圖不支持dark mode,我們app的dark mode就會顯得很雞肋,dark mode 官方說對OLED屏幕可以增加電池續(xù)航,除此之外開發(fā)者app支持的好壞決定這個功能是否雞肋。
1.2 對于dark mode的支持蘋果爸爸官方是什么態(tài)度呢,

Supporting both light and dark appearances is a good practice, but you might have good reasons to opt out of appearance changes wholly or partially in your app. Views containing user-created content should always reflect the user’s choices. Similarly, you might choose a specific appearance for print-related views so that they reflect what the user sees on the printed page
The system assumes that apps linked against the iOS 13 or later SDK support both light and dark appearances. In iOS, you specify the specific appearance you want by assigning a specific interface style to your window, view, or view controller. You can also disable support for Dark Mode entirely using an Info.plist key.

The system automatically opts in any app linked against the iOS 13.0 or later SDK to both light and dark appearances. If you need extra time to work on your app's Dark Mode support, you can temporarily opt out by including the UIUserInterfaceStyle key (with a value of Light) in your app’s Info.plist file. Setting this key to Light causes the system to ignore the user's preference and always apply a light appearance to your app.

Important
Supporting Dark Mode is strongly encouraged. Use the UIUserInterfaceStyle key to opt out only temporarily while you work on improvements to your app's Dark Mode support.

蘋果爸爸說了這個功能是被強烈建議的,默認是需要你支持的,如果你時間不夠的話,就可以先在plist里配置暫時不支持dark mode,除非你的應(yīng)用真的不需要支持,比如打印界面,以后如果不支持會不會被拒都不好說,建議開發(fā)者未雨綢繆吧。

2.技術(shù)支持

對于dark mode的支持,其實有兩種方法可以實現(xiàn)(目前還不明確不用系統(tǒng)的API支持dark mode是否可以):
2.1、在蘋果出來黑暗模式之前,就有很多app支持夜間模式,尤其是閱讀類的app. 在Github上有一個三方的庫專門支持夜間模式,星星數(shù)還挺多,大家可以看一下DKNightVersion
2.2、本節(jié)的重點就是來介紹一下iOS13系統(tǒng)的API對dark mode的支持
首先我們簡單說一下對webContent的Dark mode的支持【W(wǎng)WDC視頻鏈接地址】,中文的webcontent深色模式適配可以參考博客:為你的網(wǎng)頁添加深色模式--點我
2.3 iOS13原生API的支持:

2.3.1對顏色的支持:
在iOS13官方增加了dynamic color,動態(tài)顏色就是在dark mode和light mode模式下其值是不一樣的, 而且模式切換后,系統(tǒng)會給你重新界面渲染。大家可以看一下官方UIColor類文件對顏色的定義。
對顏色的支持主要有兩種方式,第一種比較簡單:

顏色在color set里設(shè)置

在上面添加一個color set, 然后用代碼就可以獲取dynamic color了

 UIColor *dynamicColor = [UIColor colorNamed:@"dynamicClolor"];

第二種就是Choose semantic colors instead of fixed color values.主要區(qū)分了1、System colors 2、 Foreground colors 3、Background colors 4、Fill colors 5、Other colors

  • System colors 包含了system開頭的一些顏色, 一定要注意這些顏色的色值根據(jù)背景紋理會是不同的!
  • Foreground colors包含了一些要展示的顏色,包含四個級別的labelColor和linkColor以及placeholderTextColor、separatorColor,opaqueSeparatorColor
  • Background colors包含了三個級別的systemBackgroundColor 和三個級別的systemGroupedBackgroundColor
  • Fill colors包含了四個級別的systemFillColor
  • Other colors包含了lightTextColor,darkTextColor這些color不會隨著模式的更改而更改

如果你們打算使用蘋果官方給出的顏色進行app開發(fā),您可以參考下官方對顏色的使用說明,也可以參考
這篇文章關(guān)于新增iOS 13 Dark Mode API的那些事

light mode和dark mode顏色展示對比

當(dāng)然蘋果給出了這五種類型的顏色不能滿足我們設(shè)計的小賊眼,所以蘋果官方給出了自己生成dynamic color的API:

@interface UIColor (DynamicColors)

/* 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 *))dynamicProvider API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
- (UIColor *)initWithDynamicProvider:(UIColor * (^)(UITraitCollection *))dynamicProvider API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);

/* Resolve any color to its most fundamental form (a non-dynamic color) for a specific trait collection.
*/
- (UIColor *)resolvedColorWithTraitCollection:(UITraitCollection *)traitCollection API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
@end
============================================================================================================================
//dynamic color API example:
       UIColor *dyColor = [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull trainCollection) {
           if ([trainCollection userInterfaceStyle] == UIUserInterfaceStyleLight) {
               return [UIColor blackColor];
           }
           else {
               return [UIColor whiteColor];
           }
       }];
        [self addLabelWithSuperView:scrollView andtext:[NSString stringWithFormat:@"%@",@"dyColor"] andframe:CGRectMake(15, 10, 160, 30) andtag:10 andTextcolor:dyColor];

============================================================================================================================

2.3.2對圖片的支持(Providing Images for Different Appearances):

Asset完美的支持了黑暗模式,但是放在bundle里的圖片如何命名也支持黑暗模式呢?這個就不知道有沒有方法了,如果大家有知道的,可以給我留言

2.3.3對毛玻璃效果的支持

對毛玻璃效果的支持
@interface UIVibrancyEffect (AdditionalStyles)
//+ (UIVibrancyEffect *)effectForBlurEffect:(UIBlurEffect )blurEffect style:(UIVibrancyEffectStyle)style API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos);
@end
/

* Blur styles available in iOS 13.
*
* Styles which automatically adapt to the user interface style:
/
UIBlurEffectStyleSystemUltraThinMaterial API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos),
UIBlurEffectStyleSystemThinMaterial API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos),
UIBlurEffectStyleSystemMaterial API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos),
UIBlurEffectStyleSystemThickMaterial API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos),
UIBlurEffectStyleSystemChromeMaterial API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos),
/
And always-light and always-dark versions:
*/
UIBlurEffectStyleSystemUltraThinMaterialLight API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos),
UIBlurEffectStyleSystemThinMaterialLight API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos),
UIBlurEffectStyleSystemMaterialLight API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos),
UIBlurEffectStyleSystemThickMaterialLight API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos),
UIBlurEffectStyleSystemChromeMaterialLight API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos),
UIBlurEffectStyleSystemUltraThinMaterialDark API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos),
UIBlurEffectStyleSystemThinMaterialDark API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos),
UIBlurEffectStyleSystemMaterialDark API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos),
UIBlurEffectStyleSystemThickMaterialDark API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos),
UIBlurEffectStyleSystemChromeMaterialDark API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos, watchos),

DEB15BD622EDD6C4FCAC418E7D106745.png

2.3.4:默認系統(tǒng)的控件,像tabbar,navigationbar,slide, 對黑暗模式是支持的。
2.3.5:dark mode change some method will be called ,like these:

5BC300852AF81235C8DCF044EA6B5F4F.png

2.3.6: Resolving Dynamic Colors

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection)
if traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) { // Resolve dynamic colors again
} }

Resolving Dynamic Colors
let dynamicColor = UIColor.systemBackground
let traitCollection = view.traitCollection
let resolvedColor = dynamicColor.resolvedColor(with: traitCollection)

let layer = CALayer()
let traitCollection = view.traitCollection
// Option 1
let resolvedColor = UIColor.label.resolvedColor(with: traitCollection)
layer.borderColor = resolvedColor.cgColor

let layer = CALayer()
let traitCollection = view.traitCollection
// Option 2
}
traitCollectionperformAsCurrent{
layer.boaderColor = UIcolor.label.cgclolor
}

let layer = CALayer()
let traitCollection = view.traitCollection
// Option 3
UITraitCollection.current = traitCollection
layer.borderColor = UIColor.label.cgColor

Resolving Dynamic Images
let image = UIImage(named: "HeaderImage")
let asset = image?.imageAsset
let resolvedImage = asset?.image(with: traitCollection)

2.3.7:Choosing a Specific Interface Style for Your iOS App

Override the Interface Style for a Window, View, or View Controller

When your interface must always appear in a light or dark style, regardless of the system setting, set the overrideUserInterfaceStyle property of the appropriate window, view, or view controller to that style. Overriding the interface style affects other objects in your interface as follows:

  • View controllers—The view controller’s views and child view controllers adopt the style.

  • Views—The view and all of its subviews adopt the style.

  • Windows—Everything in the window adopts the style, including the root view controller and all presentation controllers that display content in that window.

The following code example enables a light appearance for a view controller and all of its views.

    override func viewDidLoad() {
        super.viewDidLoad()

        // Always adopt a light interface style.    
        overrideUserInterfaceStyle = .light
    }

Override the Interface Style for Child View Controllers

Parent view controllers control the appearance of their contained child view controllers. To override the interface style for a child view controller, use the setOverrideTraitCollection:forChildViewController: method to assign new traits to that view controller. For custom presentations, you can similarly override the interface style of the presented view controller by assigning new traits to the overrideTraitCollection property of your UIPresentationController object.

2.3.8:對于UILabel、UITextField、UITextView,在設(shè)置NSAttributedString時也要考慮適配Dark Mode,否則在切換模式時會與背景色融合,造成不好的體驗

NSDictionary *dic = @{NSFontAttributeName:[UIFont systemFontOfSize:16],NSForegroundColorAttributeName:[UIColor labelColor]};
NSAttributedString *str = [[NSAttributedString alloc] initWithString:@"富文本文案" attributes:dic];

2.3.9:獲取當(dāng)前模式

if (UITraitCollection.currentTraitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {
        [self.titleLabel setText:@"DarkMode"];
    }
    else {
        [self.titleLabel setText:@"LightMode"];
    }

2.3.10模式切換時打印系統(tǒng)log日志
在Xcode菜單欄Product->Scheme->Edit Scheme
選擇Run->Arguments->Arguments Passed On Launch
添加以下命令即可
-UITraitCollectionChangeLoggingEnabled YES

總結(jié):Use UIKit colors, materials, views, and controls Customize colors and images when necessary

==================================================================================
參考:

1、https://developer.apple.com/documentation/appkit/supporting_dark_mode_in_your_interface?language=objc

2、Choosing a Specific Interface Style for Your iOS App

3、https://developer.apple.com/videos/play/wwdc2019/214

4、關(guān)于新增iOS 13 Dark Mode API的那些事 http://www.itdecent.cn/p/83e7fa45b0a2

5、https://blog.csdn.net/ios8988/article/details/92422826

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 把月亮分出來 一杯敬過往的銹跡斑斑, 一杯放蕩 凝重的靈魂無處安放 泥封的酒壇 剩下落雪,剩下秋天的嘆息 不忍打碎...
    羅子閱讀 433評論 8 39
  • 昨天送別一位同事。場面比較熱烈,同事很聰明,很勤勞,在工會和部門工作中都極其出類拔萃,讓大家非常不舍。 正好10年...
    靠譜陳老師閱讀 654評論 1 48
  • 記住,懶惰的人是無法在2014年稱霸世界的! 無論身處哪個行業(yè),不論世界如何變遷,只要您積極的迎合不斷變化的消費者...
    東風(fēng)知我閱讀 558評論 0 1
  • 今日,雨過天晴,陽光燦爛。騎行在路上,穿梭在這小城的風(fēng)里,一路上看到好幾條可愛的小狗狗,有黑色,白色,黃色,但是它...
    愛若是花閱讀 489評論 2 3

友情鏈接更多精彩內(nèi)容