日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

iOS开发 DarkMode 暗黑模式

發(fā)布時(shí)間:2024/3/13 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 iOS开发 DarkMode 暗黑模式 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、開發(fā)環(huán)境

Xcode11 正式版 iOS13 beta版本 Mac系統(tǒng): 10.15 beta版本

二、適配原理

  • 將同一個(gè)資源,創(chuàng)建出兩種模式的樣式。系統(tǒng)根據(jù)當(dāng)前選擇的樣式,自動獲取該樣式的資源。
  • 每次系統(tǒng)更新樣式時(shí),應(yīng)用會調(diào)用當(dāng)前所有存在的元素調(diào)用對應(yīng)的一些重新方法,進(jìn)行重繪視圖,可以在對應(yīng)的方法做相應(yīng)的改動

三、資源適配

step1、顏色適配 通過 Assets 配置

在 iOS 11和 Xcode 9 中,我們可以在 Images.xcassets 中添加顏色。
現(xiàn)在我們可以為顏色再配置一個(gè)用于暗黑模式的對應(yīng)的顏色。

我們可以選擇 (原彩,深色) 或者 (原彩,深色,夜覽)

step2、圖片適配

打開Assets.xcassets,新建一個(gè)Image set,打開右側(cè)工具欄,點(diǎn)擊最后一欄,找到Appearances,同樣可以選擇 (原彩,深色) 或者 (原彩,深色,夜覽),然后在對應(yīng)的位置添加圖片

四、代碼適配

step1、UIColor 適配 語義化顏色介紹加代碼展示

iOS13 之前 UIColor只能表示一種顏色,而從 iOS13 開始UIColor是一個(gè)動態(tài)的顏色,在Light Mode和Dark Mode可以分別設(shè)置不同的顏色。
iOS13系統(tǒng)提供了一些動態(tài)顏色。蘋果引入了全新系統(tǒng)顏色和一套根據(jù)顏色使用目的而約定顏色命名的語義化顏色

#pragma mark - 語義化顏色 @property (class, nonatomic, readonly) UIColor *systemBrownColor @property (class, nonatomic, readonly) UIColor *systemIndigoColor @property (class, nonatomic, readonly) UIColor *systemGray2Color @property (class, nonatomic, readonly) UIColor *systemGray3Color @property (class, nonatomic, readonly) UIColor *systemGray4Color @property (class, nonatomic, readonly) UIColor *systemGray5Color @property (class, nonatomic, readonly) UIColor *systemGray6Color @property (class, nonatomic, readonly) UIColor *labelColor @property (class, nonatomic, readonly) UIColor *secondaryLabelColor @property (class, nonatomic, readonly) UIColor *tertiaryLabelColor @property (class, nonatomic, readonly) UIColor *quaternaryLabelColor @property (class, nonatomic, readonly) UIColor *linkColor @property (class, nonatomic, readonly) UIColor *placeholderTextColor @property (class, nonatomic, readonly) UIColor *separatorColor @property (class, nonatomic, readonly) UIColor *opaqueSeparatorColor @property (class, nonatomic, readonly) UIColor *systemBackgroundColor @property (class, nonatomic, readonly) UIColor *secondarySystemBackgroundColor @property (class, nonatomic, readonly) UIColor *tertiarySystemBackgroundColor @property (class, nonatomic, readonly) UIColor *systemGroupedBackgroundColor @property (class, nonatomic, readonly) UIColor *secondarySystemGroupedBackgroundColor @property (class, nonatomic, readonly) UIColor *tertiarySystemGroupedBackgroundColor @property (class, nonatomic, readonly) UIColor *systemFillColor @property (class, nonatomic, readonly) UIColor *secondarySystemFillColor @property (class, nonatomic, readonly) UIColor *tertiarySystemFillColor @property (class, nonatomic, readonly) UIColor *quaternarySystemFillColor

IOS13系統(tǒng)UIColor增加了兩個(gè)初始化方法,使用以下方法可以創(chuàng)建動態(tài)UIColor
注:一個(gè)是類方法,一個(gè)是實(shí)例方法,兩個(gè)方法如下:

+ (UIColor *)colorWithDynamicProvider:(UIColor * (^)(UITraitCollection *traitCollection))dynamicProvider - (UIColor *)initWithDynamicProvider:(UIColor * (^)(UITraitCollection *traitCollection))dynamicProvider

可以在 block 中判斷 traitCollection.userInterfaceStyle,根據(jù)系統(tǒng)模式設(shè)置返回的顏色。userInterfaceStyle,是一個(gè)枚舉類型,會告訴我們當(dāng)前是LightMode還是DarkMode

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

例子

UIColor *color = [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull traitCollection) {if (traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {return [UIColor blackColor];} else {return [UIColor whiteColor];}}];

step2、CGColor 適配

我們知道iOS13后,UIColor能夠表示動態(tài)顏色,但是CGColor依然只能表示一種顏色,那么對于CALayer等對象如何適配暗黑模式呢?這里提供兩個(gè)方法供大家參考:
(1)、通過方法resolvedColorWithTraitCollection得到對應(yīng)UIColor,再將UIColor轉(zhuǎn)換為CGColor

UIColor *resolvedColor = [dyColor resolvedColorWithTraitCollection:previousTraitCollection]; layer.backgroundColor = resolvedColor.CGColor;

(2)、直接設(shè)置為一個(gè)動態(tài)UIColor的CGColor即可

- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {[super traitCollectionDidChange:previousTraitCollection];UIColor *dyColor = [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull trainCollection) {if ([trainCollection userInterfaceStyle] == UIUserInterfaceStyleLight) {return [UIColor redColor];} else {return [UIColor greenColor];}}];layer.backgroundColor = dyColor.CGColor; }

?? 注意!!! 我們需要為layer設(shè)置一個(gè)基本顏色,因?yàn)閮蓚€(gè)方法都是在traitCollectionDidChange中設(shè)置layer的顏色,那么如果沒有發(fā)生模式切換,layer將會沒有顏色

五、獲取當(dāng)前模式以及UITraitCollection介紹,監(jiān)聽模式切換

在 iOS 13 中,我們可以通過 UITraitCollection 來判斷當(dāng)前系統(tǒng)的模式。UIViewUIViewController 、UIScreen、UIWindow 都已經(jīng)遵從了UITraitEnvironment 這個(gè)協(xié)議,因此這些類都擁有一個(gè)叫做 traitCollection 的屬性,在這些類中,我們可以這樣去判斷當(dāng)前 App 的顏色模式:

BOOL isDark = (self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark);

另外,我們還可以通過 UITraitCollection.current 這個(gè)屬性來獲取當(dāng)前 App 的顏色模式但是并不是所有的時(shí)候獲取的都是正確的,只有在下面這些方法中,才可以放心的使用這個(gè)屬性:

還沒適配完又不想給用戶看,可以先暫時(shí)全局關(guān)閉暗黑模式:在 Info.plist 文件中,添加 key 為 User Interface Style,類型為 String,value 設(shè)置為 Light 即可。
有時(shí)我們需要監(jiān)聽系統(tǒng)模式的變化,并作出響應(yīng)
那么我們就需要在需要監(jiān)聽的viewController中,重寫下列函數(shù)

#pragma mark - 監(jiān)聽系統(tǒng)模式變化 // ?? 參數(shù)為變化前的traitCollection - (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection;#pragma mark - 判斷兩個(gè)UITraitCollection對象是否不同 - (BOOL)hasDifferentColorAppearanceComparedToTraitCollection:(UITraitCollection *)traitCollection;

示例代碼

- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {[super traitCollectionDidChange:previousTraitCollection];// trait發(fā)生了改變if ([self.traitCollection hasDifferentColorAppearanceComparedToTraitCollection:previousTraitCollection]) {// 執(zhí)行操作} }

在 iOS 13中,UIView、UIViewController 、UIWindow 有了一個(gè) overrideUserInterfaceStyle 的新屬性,可以覆蓋系統(tǒng)的模式

單個(gè)頁面或視圖關(guān)閉暗黑模式,設(shè)置 overrideUserInterfaceStyle 為對應(yīng)的模式,強(qiáng)制限制該視圖與其子視圖以設(shè)置的模式進(jìn)行展示,不跟隨系統(tǒng)模式改變進(jìn)行改變。
示例代碼

self.overrideUserInterfaceStyle = UIUserInterfaceStyleLight;

?? 注意!!!

  • 當(dāng)我們強(qiáng)行設(shè)置當(dāng)前viewController為Dark Mode后,這個(gè)viewController下的view都是Dark Mode
  • 由這個(gè)ViewController present出的ViewController不會受到影響,依然跟隨系統(tǒng)的模式
  • 要想一鍵設(shè)置App下所有的ViewController都是Dark Mode,請直接在Window上執(zhí)行overrideUserInterfaceStyle
  • 對window.rootViewController強(qiáng)行設(shè)置Dark Mode也不會影響后續(xù)present出的ViewController的模式

六、擴(kuò)展

step1、模糊效果

  • 在 iOS 中,我們創(chuàng)建模糊效果的 UIVisualEffectView 的代碼也會有明確表面明暗的情況。我們需要讓這些模糊效果隨著系統(tǒng)模式的切換而切換。UIKit 提供了新的模糊樣式且是動態(tài)的,會隨著系統(tǒng)模式的改版而自動匹配。
  • 在利用 UIVisualEffectView 來創(chuàng)建一些類似模糊的效果時(shí),不要設(shè)置類似 UIBlurEffectStyleExtraLight 這樣帶有明確顏色的效果,而是設(shè)置 UIKit 中新提供的動態(tài)樣式的效果,比如 UIBlurEffectStyleSystemThinMaterialLight 或 UIBlurEffectStyleSystemThinMaterialDark。
UIBlurEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemMaterial]; UIVisualEffectView *effectView = [[UIVisualEffectView alloc] initWithEffect:effect];

step2、啟動圖

如果我們的 App 使用了 LaunchImage 作為啟動屏,那么就應(yīng)該考慮把 LaunchImage 換成 LaunchScreen.storyboard 了,因?yàn)樵?Xcode 11 中 LaunchImage 并不能像普通的圖片那樣針對深色模式設(shè)置另外的一張圖片。

step3、富文本

給 Attributed String 加上一個(gè) foregroundColor 屬性,設(shè)置動態(tài)的顏色即可。

[attr addAttribute:NSForegroundColorAttributeName value:[UIColor labelColor] range:NSMakeRange(10, 20)];

step4、調(diào)試 dark mode

storyboards 和 xib 文件,現(xiàn)在可以切換界面之間的樣式是默認(rèn)還是暗黑了。

在模擬器上,也可以直接切換暗黑模式進(jìn)行調(diào)試了。

step5、模式切換打印

  • 模式切換時(shí)自動打印log,就不需要我們一次又一次的執(zhí)行po命令了
  • 在Xcode菜單欄Product->Scheme->Edit Scheme
    選擇Run->Arguments->Arguments Passed On Launch
    添加以下命令即可
  • UITraitCollectionChangeLoggingEnabled YES

step6、Demo地址 YQDarkModeDemo

總結(jié)

以上是生活随笔為你收集整理的iOS开发 DarkMode 暗黑模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。