iOS 13-暗黑模式適配

一夸盟、源起

蘋果公司要求酱塔,在5月之前必須完成對于iOS13新增的暗黑模式適配。來源于http://www.cocoachina.com/articles/896909?filter=rec弟蚀。這里趁有時間拌消,找了點(diǎn)資料挑豌。大概屢了一下邏輯。不過按照蘋果的尿性。估計(jì)不會這么快就要求氓英。

二侯勉、適配原理

    將同一個資源,創(chuàng)建出兩種模式的樣式铝阐。系統(tǒng)根據(jù)當(dāng)前選擇的樣式址貌,自動獲取該樣式的資源。
    每次系統(tǒng)更新樣式時徘键,應(yīng)用會調(diào)用當(dāng)前所有存在的元素調(diào)用對應(yīng)的一些重新方法练对,進(jìn)行重繪視圖,可以在對應(yīng)的方法做相應(yīng)的改動啊鸭。根據(jù)系統(tǒng)新增的一些通知方法和對于一些主要顯示類新增的刷新方法 做一些判斷處理锹淌。

三、圖片適配

1.創(chuàng)建一個Assets文件(或在現(xiàn)有的Assets文件中)
2.新建一個圖片資源文件(或者顏色資源文件赠制、或者其他資源文件)
3.選中該資源文件赂摆, 打開 Xcode ->View ->Inspectors ->Show Attributes Inspectors (或者Option+Command+4)視圖,將 Apperances 選項(xiàng) 改為Any钟些,Dark


3.png

4.執(zhí)行完第三步烟号,資源文件將會有多個容器框,分別為 Any Apperance 和 Dark Apperance. Any Apperance 應(yīng)用于默認(rèn)情況(Unspecified)與高亮情況(Light)政恍, Dark Apperance 應(yīng)用于暗黑模式(Dark)


4.png

代碼默認(rèn)執(zhí)行時汪拥,就可以正常通過名字使用了,系統(tǒng)會根據(jù)當(dāng)前模式自動獲取對應(yīng)的資源文件篙耗。

四迫筑、顏色適配

iOS13之前的UIColor 只能返回一種特定的顏色,iOS13及其以后可以返回動態(tài)的顏色
UIColor增加了兩個初始化方法宗弯,使用以下方法可以創(chuàng)建動態(tài)UIColor
注:一個是類方法脯燃,一個是實(shí)例方法,兩個方法如下:

+ (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);

方法需要傳一個block
當(dāng)系統(tǒng)在LightModel 跟DarkMode中進(jìn)行切換的時候蒙保,會立刻回調(diào)這個方法(應(yīng)用不管處于前臺還是后臺)
block中返回當(dāng)前的traitCollection對象辕棚,我們根據(jù)它的屬性userInterfaceStyle 判斷當(dāng)前的顯示模式,block中返回對應(yīng)模式下的color
UIUserInterfaceStyle 枚舉類型如下:

typedef NS_ENUM(NSInteger, UIUserInterfaceStyle) {
    UIUserInterfaceStyleUnspecified,
    UIUserInterfaceStyleLight,
    UIUserInterfaceStyleDark,
}

示例代碼??

-(void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
    NSLog(@"traitCollectionDidChange");
   //創(chuàng)建動態(tài) color
    UIColor *color = [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull traitCollection) {
        if (traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {
            return [UIColor darkGrayColor];
        } else {
            return [UIColor redColor];
        }

    }];
    self.view.backgroundColor = color;

}

五、繪圖適配

iOS13后邓厕,UIColor能夠表示動態(tài)顏色逝嚎,但是CGColor依然只能表示一種顏色,那么對于CALayer等對象如何適配暗黑模式呢?
有幾下三種方式進(jìn)行表示
方法如下:

-(void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
    NSLog(@"traitCollectionDidChange");
    if (@available(iOS 13.0, *)) {
        //創(chuàng)建動態(tài) bgColor
        UIColor *bgColor = [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull traitCollection) {
            if (traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {
                return [UIColor blackColor];
            } else {
                return [UIColor whiteColor];
            }
        }];
        self.view.backgroundColor = bgColor;
        //創(chuàng)建動態(tài) layerColor
        UIColor *layerColor = [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull traitCollection) {
            if (traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {
                return [UIColor darkGrayColor];
            } else {
                return [UIColor redColor];
            }
        }];
        //改變layer 顏色
            //1.方法一
        //    UIColor *resolveColor = [layerColor resolvedColorWithTraitCollection:self.traitCollection];
        //    layer.backgroundColor = resolveColor.CGColor;
            //2.方法二
        //    [self.traitCollection performAsCurrentTraitCollection:^{
        //        UIColor *resolveColor = [layerColor resolvedColorWithTraitCollection:self.traitCollection];
        //        layer.backgroundColor = resolveColor.CGColor;
        //    }];
            //3.方法三
            layer.backgroundColor = layerColor.CGColor;
    } else {
        NSLog(@"不是iOS13 所以不需要暗黑模式");
    }
}

六详恼、刷新掉用

當(dāng)用戶更改外觀時补君,系統(tǒng)會通知所有window與View需要更新樣式,在此過程中iOS會觸發(fā)以下方法, 完整的觸發(fā)方法文檔

UIView:中可以調(diào)用如下方法進(jìn)行更改

traitCollectionDidChange(_:)
layoutSubviews()
draw(_:)
updateConstraints()
tintColorDidChange()

UIViewController:中可以調(diào)用如下方法進(jìn)行更改

traitCollectionDidChange(_:)
updateViewConstraints()
viewWillLayoutSubviews()
viewDidLayoutSubviews()

UIPresentationController:中可以調(diào)用如下方法進(jìn)行更改

traitCollectionDidChange(_:)
containerViewWillLayoutSubviews()
containerViewDidLayoutSubviews()

七昧互、幾種常見適配方式

1> 默認(rèn)情況下應(yīng)用不做任何處理是需要跟隨手機(jī)系統(tǒng)做暗黑適配
2> 如果整個應(yīng)用中堅(jiān)持是Light 或者Dark模式赚哗,需要在info.plist
中 添加 UIUserInterfaceStyle 為 Light 或者Dark
3> 部分UIView / UIViewcontroller / UIWindow 不跟隨手機(jī)暗黑適配

a.UIViewController與UIView 都新增一個屬性 -overrideUserInterfaceStyle
b.將 -overrideUserInterfaceStyle 設(shè)置為對應(yīng)的模式她紫,則強(qiáng)制限制該元素與其子元素以設(shè)置的模式進(jìn)行展示,不跟隨系統(tǒng)模式改變進(jìn)行改變
c.-overrideUserInterfaceStyle影響范圍屿储。

設(shè)置 ViewController 的該屬性, 將會影響視圖控制器的視圖和子視圖控制器采用該樣式渐逃,不影響彈出的vc
設(shè)置 View 的該屬性够掠, 將會影響視圖及其所有子視圖采用該樣式
設(shè)置 Window 的該屬性, 將會影響窗口中的所有內(nèi)容都采用樣式茄菊,包括根視圖控制器和在該窗口中顯示內(nèi)容的所有演示控制器(UIPresentationController)

/*
* When set on an ordinary `UIView`:
 * - This property affects only the traits of this view and its subviews.
 * - It does not affect any view controllers, or any subviews that are owned by different view controllers.
 *
 * When set on a `UIWindow`:
 * - This property affects the `rootViewController` and thus the entire view controller and view hierarchy.
 * - It also affects presentations that happen inside the window.
 */
@property (nonatomic) UIUserInterfaceStyle overrideUserInterfaceStyle API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchOS);

八疯潭、自動輸出log

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


5.png

當(dāng)切換模式就會在控制臺打印出信息面殖,信息如下:


6.png

九竖哩、相關(guān)資料

demo: https://github.com/sisios/DarkModel.git
WWDC視頻:https://developer.apple.com/videos/play/wwdc2019/214/
http://www.reibang.com/p/7925bd51d2d6
http://www.reibang.com/p/e6616e44cf60
http://www.reibang.com/p/476cac3851c8

十、項(xiàng)目實(shí)戰(zhàn)

我們項(xiàng)目用的DKNightVersion三方適配夜間模式脊僚,為了更好的兼容iOS13暗黑模式相叁,我在第一個頁簽的viewcontroller的重寫*-(void)traitCollectionDidChange:(UITraitCollection )previousTraitCollection方法

當(dāng)app被殺死,修改暗黑模式后辽幌,重啟app

-(void)applicationDidFinishLaunching:(UIApplication *)application {
    //暗黑模式
    if (@available(iOS 13.0, *)) {
        UIUserInterfaceStyle style = UITraitCollection.currentTraitCollection.userInterfaceStyle;
        if (style == UIUserInterfaceStyleDark) {
            [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"showNightMode"];
           
            [self.dk_manager nightFalling];
        } else {
            [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"showNightMode"];
            [self.dk_manager dawnComing];
        }
    } else {
        NSLog(@"不是iOS13增淹,不需要暗黑模式");
    }
}

當(dāng)app處于active(前臺或者后臺)

//暗黑模式
-(void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
    NSLog(@"traitCollectionDidChange");
   //創(chuàng)建動態(tài) color
    if (@available(iOS 13.0, *)) {
        UIColor *color = [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull traitCollection) {
            if (traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {
                [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"showNightMode"];
                
                [self.dk_manager nightFalling];
                return [UIColor blackColor];
            } else {
                [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"showNightMode"];
                
                [self.dk_manager dawnComing];
                return [UIColor whiteColor];
            }
        }];
        self.view.backgroundColor = color;
    } else {
        NSLog(@"不是iOS13版本不需要暗黑模式");
    }

}

注意點(diǎn)

項(xiàng)目中全部使用了UIColor的地方一定要注意了。一些默認(rèn)的顏色 比如Cell背景色 UIView背景色 不要在設(shè)置白色 這樣他們顏色就跟隨系統(tǒng)的 顏色顯示 自動切換了乌企。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末虑润,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子加酵,更是在濱河造成了極大的恐慌拳喻,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件猪腕,死亡現(xiàn)場離奇詭異冗澈,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)码撰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門渗柿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人脖岛,你說我怎么就攤上這事朵栖。” “怎么了柴梆?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵陨溅,是天一觀的道長。 經(jīng)常有香客問我绍在,道長门扇,這世上最難降的妖魔是什么雹有? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮臼寄,結(jié)果婚禮上霸奕,老公的妹妹穿的比我還像新娘。我一直安慰自己吉拳,他們只是感情好质帅,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著留攒,像睡著了一般煤惩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上炼邀,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天魄揉,我揣著相機(jī)與錄音,去河邊找鬼拭宁。 笑死洛退,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的红淡。 我是一名探鬼主播不狮,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼在旱!你這毒婦竟也來了摇零?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤桶蝎,失蹤者是張志新(化名)和其女友劉穎驻仅,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體登渣,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡噪服,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了胜茧。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片粘优。...
    茶點(diǎn)故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖呻顽,靈堂內(nèi)的尸體忽然破棺而出雹顺,到底是詐尸還是另有隱情,我是刑警寧澤廊遍,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布嬉愧,位于F島的核電站,受9級特大地震影響喉前,放射性物質(zhì)發(fā)生泄漏没酣。R本人自食惡果不足惜王财,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望裕便。 院中可真熱鬧绒净,春花似錦、人聲如沸闪金。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽哎垦。三九已至,卻和暖如春恃疯,著一層夾襖步出監(jiān)牢的瞬間漏设,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工今妄, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留郑口,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓盾鳞,卻偏偏與公主長得像犬性,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子腾仅,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 1.環(huán)境 Xcode11 正式版iOS13 beta版本Mac系統(tǒng): 10.15 beta版本 2.原理 將同一個...
    329fd8af610c閱讀 11,631評論 0 17
  • 隨著iPhone 11的發(fā)布乒裆,iOS 13適配也提上了日程,剛好最近在做項(xiàng)目適配推励,順便總結(jié)一下:首先升級Xcode...
    二豬哥閱讀 6,218評論 2 36
  • 暗黑模式 原理 將同一個資源鹤耍,創(chuàng)建出兩種模式的樣式。系統(tǒng)根據(jù)當(dāng)前選擇的樣式验辞,自動獲取該樣式的資源 每次系統(tǒng)更新樣式...
    Y筱鵬Y閱讀 58,702評論 14 62
  • 9月20號iOS 13 已正式發(fā)布稿黄,第一時間更新了最新系統(tǒng),網(wǎng)上對其用戶體驗(yàn)上的新特性的描述也很多跌造,而對于開發(fā)者來...
    杰小冷_4957閱讀 573評論 0 2
  • 前提概要: 使用mpvue來寫小程序的代碼 我的需求 首先杆怕,小程序的picker目前只支持index來定位選中的值...
    小陳陳醬閱讀 1,193評論 4 1