IOS屏幕適配(四)最新系統(tǒng)IOS13適配

@TOC

3. IOS 最新系統(tǒng)適配問題

  • 蘋果官方資料:
  1. WWDC19視頻
  2. Xcode 11 beta 下載
  3. macOS Catalina 10.15 beta 下載

3.1 IOS 13 適配

3.1.1 即將廢棄的 LaunchImage

從 iOS 8 的時(shí)候趟大,蘋果就引入了 LaunchScreen锐想,我們可以設(shè)置 LaunchScreen來作為啟動(dòng)頁(yè)绷杜。當(dāng)然,現(xiàn)在你還可以使用LaunchImage來設(shè)置啟動(dòng)圖鸭丛。不過使用LaunchImage的話,要求我們必須提供各種屏幕尺寸的啟動(dòng)圖,來適配各種設(shè)備,隨著蘋果設(shè)備尺寸越來越多缩举,這種方式顯然不夠 Flexible。而使用 LaunchScreen的話,情況會(huì)變的很簡(jiǎn)單仅孩, LaunchScreen是支持AutoLayout+SizeClass的托猩,所以適配各種屏幕都不在話下。

  • <font face="黑體" color=red size=3>注意啦??辽慕,從2020年4月開始京腥,所有使? iOS13 SDK的 App將必須提供 LaunchScreen,LaunchImage即將退出歷史舞臺(tái)*</font>溅蛉。

3.1.2 Sign in with Apple -提供第三方登錄的注意啦

<font face="黑體" color=red size=3>如果你的應(yīng)用使用了第三方登錄公浪,那么你可能也需要加下 「Sign in with Apple」
Sign In with Apple will be available for beta testing this summer. It will be required as an option for users in apps that support third-party sign-in when it is commercially available later this year.</font>

3.1.3 iOS 13 DeviceToken有變化

NSString *dt = [deviceToken description];
dt = [dt stringByReplacingOccurrencesOfString: @"<" withString: @""];
dt = [dt stringByReplacingOccurrencesOfString: @">" withString: @""];
dt = [dt stringByReplacingOccurrencesOfString: @" " withString: @""];
<font face="黑體" color=red size=3>這段代碼運(yùn)行在 iOS 13 上已經(jīng)無法獲取到準(zhǔn)確的DeviceToken字符串了,iOS 13 通過[deviceToken description]獲取到的內(nèi)容已經(jīng)變了温艇。</font>

  • 解決方案
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
    if (![deviceToken isKindOfClass:[NSData class]]) return;
    const unsigned *tokenBytes = [deviceToken bytes];
    NSString *hexToken = [NSString stringWithFormat:@"%08x%08x%08x%08x%08x%08x%08x%08x",
                          ntohl(tokenBytes[0]), ntohl(tokenBytes[1]), ntohl(tokenBytes[2]),
                          ntohl(tokenBytes[3]), ntohl(tokenBytes[4]), ntohl(tokenBytes[5]),
                          ntohl(tokenBytes[6]), ntohl(tokenBytes[7])];
    NSLog(@"deviceToken:%@",hexToken);
}

3.1.4 MPMoviePlayerController 在iOS 13已經(jīng)不能用了

<font face="黑體" color=red size=3>'MPMoviePlayerController is no longer available. Use AVPlayerViewController in AVKit.' </font>

  • 解決方案:

既然不能再用了因悲,那只能換掉了。替代方案就是AVKit里面的那套播放器勺爱。

3.1.5 控制器的 modalPresentationStyle 默認(rèn)值變了

查閱了下 UIModalPresentationStyle枚舉定義晃琳,赫然發(fā)現(xiàn)iOS 13新加了一個(gè)枚舉值:

typedef NS_ENUM(NSInteger, UIModalPresentationStyle) {
    UIModalPresentationFullScreen = 0,
    UIModalPresentationPageSheet API_AVAILABLE(ios(3.2)) API_UNAVAILABLE(tvos),
    UIModalPresentationFormSheet API_AVAILABLE(ios(3.2)) API_UNAVAILABLE(tvos),
    UIModalPresentationCurrentContext API_AVAILABLE(ios(3.2)),
    UIModalPresentationCustom API_AVAILABLE(ios(7.0)),
    UIModalPresentationOverFullScreen API_AVAILABLE(ios(8.0)),
    UIModalPresentationOverCurrentContext API_AVAILABLE(ios(8.0)),
    UIModalPresentationPopover API_AVAILABLE(ios(8.0)) API_UNAVAILABLE(tvos),
    UIModalPresentationBlurOverFullScreen API_AVAILABLE(tvos(11.0)) API_UNAVAILABLE(ios) API_UNAVAILABLE(watchos),
    UIModalPresentationNone API_AVAILABLE(ios(7.0)) = -1,
    UIModalPresentationAutomatic API_AVAILABLE(ios(13.0)) = -2,
};
  • 解決方案
  1. 如果你完全接受蘋果的這個(gè)默認(rèn)效果,那就不需要去修改任何代碼琐鲁。
  2. 如果卫旱,你原來就比較細(xì)心,已經(jīng)設(shè)置了modalPresentationStyle的值围段,那你也不會(huì)有這個(gè)影響顾翼。
  3. 對(duì)于想要找回原來默認(rèn)交互的同學(xué),直接設(shè)置如下即可:
    self.modalPresentationStyle = UIModalPresentationOverFullScreen;

3.1.6 UITextField 的私有屬性 _placeholderLabel 被禁止訪問了

  • IOS 13下調(diào)用下面代碼會(huì)導(dǎo)致閃退
[self.textField setValue:self.placeholderColor forKeyPath:@"_placeholderLabel.textColor"];

打印錯(cuò)誤信息如下:

<font face="黑體" color=red size=1>'Access to UITextField's _placeholderLabel ivar is prohibited. This is an application bug' </font>

  • 解決方案:
UITextField有個(gè)attributedPlaceholder的屬性奈泪,我們可以自定義這個(gè)富文本來達(dá)到我們需要的結(jié)果适贸。

NSMutableAttributedString *placeholderString = [[NSMutableAttributedString alloc] initWithString:placeholder attributes:@{NSForegroundColorAttributeName : self.placeholderColor}];
_textField.attributedPlaceholder = placeholderString;

<font face="黑體" color=red size=2>iOS 13 通過 KVC 方式修改私有屬性,有 Crash 風(fēng)險(xiǎn)涝桅,謹(jǐn)慎使用拜姿!并不是所有KVC都會(huì)Crash,要嘗試冯遂!</font>

3.1.7 UISearchBar顯示問題

  • SearchBar的高度只有1px
  1. <font face="黑體" color=red size=2>升級(jí)到iOS13蕊肥,UISearchController上的SearchBar顯示異常,查看后發(fā)現(xiàn)對(duì)應(yīng)的高度只有1px,目前沒找到具體導(dǎo)致的原因蛤肌,</font>
  2. 解決辦法是: 使用KVO監(jiān)聽frame值變化后設(shè)置去應(yīng)該顯示的高度
  • 黑線處理crash
  1. <font face="黑體" color=red size=2>之前為了處理搜索框的黑線問題會(huì)遍歷后刪除UISearchBarBackground壁却,在iOS13會(huì)導(dǎo)致UI渲染失敗crash;</font>
  2. 解決辦法是: 設(shè)置UISearchBarBackground的layer.contents為nil
  • TabBar紅點(diǎn)偏移
  1. <font face="黑體" color=red size=2>如果之前有通過TabBar上圖片位置來設(shè)置紅點(diǎn)位置,在iOS13上會(huì)發(fā)現(xiàn)顯示位置都在最左邊去了裸准。遍歷UITabBarButton的subViews發(fā)現(xiàn)只有在TabBar選中狀態(tài)下才能取到UITabBarSwappableImageView展东,</font>
  2. 解決辦法是: 修改為通過UITabBarButton的位置來設(shè)置紅點(diǎn)的frame

3.1.8 黑暗模式 Dark Mode

Apps on iOS 13 are expected to support dark mode
Use system colors and materials
Create your own dynamic colors and images Leverage flexible infrastructure

UI 需要出一套新交互

  • 在iOS13,為UIViewController和UIView擴(kuò)展了一個(gè)新的API-overrideUserInterfaceStyle,使用方法炒俱,官方文檔大致是這么說的:
  1. 通過設(shè)置overrideUserInterfaceStyle屬性以使該視圖及其子視圖具有特定的UIUserInterfaceStyle琅锻。但如果想要獲取當(dāng)前的UIUserInterfaceStyle卦停,需要改用traitCollection.userInterfaceStyle。
  2. 盡可能使用UIViewController上的overrideUserInterfaceStyle屬性恼蓬。僅在以下時(shí)間使用此屬性:
    (1) 在單個(gè)視圖或小視圖層次結(jié)構(gòu)上局部使用特定樣式惊完。
    (2) 您希望在整個(gè)UIWindow及其視圖控制器和模態(tài)彈出的ViewController上使用特定樣式,且不希望強(qiáng)制更改整個(gè)應(yīng)用程序具有樣式处硬。 (如果您確實(shí)希望整個(gè)應(yīng)用程序具有某種樣式小槐,請(qǐng)不要使用它,而是在Info.plist中設(shè)置UIUserInterfaceStyle鍵荷辕。)
  3. 當(dāng)設(shè)置在普通的UIView上時(shí):
    此屬性僅影響此視圖及其子視圖的特征凿跳。
    它不會(huì)影響任何視圖控制器或其他視圖控制器的子視圖。
  4. 在UIWindow上設(shè)置時(shí):
    此屬性會(huì)影響rootViewController疮方,從而影響整個(gè)視圖控制器和視圖層次結(jié)構(gòu)控嗜。
    它還會(huì)影響該window模態(tài)出來的界面。
  • 由此可見骡显,overrideUserInterfaceStyle不僅會(huì)影響自己疆栏,還會(huì)影響自己的子視圖,換做window就會(huì)影響整個(gè)window中的所有視圖及視圖控制器惫谤,包括模態(tài)跳轉(zhuǎn)出來的視圖控制器壁顶。
    而且,文檔中也特別強(qiáng)調(diào)了溜歪,你可以設(shè)置整個(gè)應(yīng)用程序只是用某種樣式若专,具體方法可以通過代碼,也可以通過info.plist配置鍵User Interface Style,對(duì)應(yīng)的ValueLight/Dark蝴猪。
if #available(iOS 13.0, *) {
    window?.overrideUserInterfaceStyle = .light;
}
image

3.1.8.1 適配黑暗模式

  • 適配Dark 模式主要從這幾個(gè)方面:
  1. 模擬器調(diào)試(simulator debug)
  2. 圖片(assets)
  3. 顏色(color)
  4. 狀態(tài)欄(status bar)
3.1.8.1.1 模擬器調(diào)試
  • 運(yùn)行項(xiàng)目,點(diǎn)擊Xcode底部調(diào)試欄中Environment Overrides.
  • 開啟Interface Style调衰,就可以切換了。如下圖:


    切換Dark模式

    模擬器打開darkMode
3.1.8.1.2 圖片適配
  • 圖片適配自阱,主要是我們本地圖片資源適配嚎莉,網(wǎng)絡(luò)圖片的話,還是比較繁瑣动壤。
  • 圖片適配比較方便的就是通過Assets.xcassets進(jìn)行圖片管理:
  1. 添加一個(gè)image set萝喘,重命名如"adaptimage"淮逻,選中該image set;
  2. 選中Attributes Inspector;
  3. 將Appearances由"None"改為"Any,Dark"琼懊;
  4. 不同模式下設(shè)置不同圖片即可,mode 改變會(huì)自動(dòng)選擇不同的圖片


    Assets.xcassets進(jìn)行圖片管理
  • 當(dāng)然圖片適配爬早,你也可以直接使用判斷當(dāng)前系統(tǒng)mode的方式進(jìn)行區(qū)分,就我個(gè)人而言不是很喜歡這種方式,因?yàn)檫€需要監(jiān)聽系統(tǒng)模式的變化再膳,重寫UITraitEnvironment協(xié)議方法traitCollectionDidChange(_:),我們先看下協(xié)議方法:
/** Trait environments expose a trait collection that describes their environment. */
public protocol UITraitEnvironment : NSObjectProtocol {

    @available(iOS 8.0, *)
    var traitCollection: UITraitCollection { get }

    /** To be overridden as needed to provide custom behavior when the environment's traits change. */
    @available(iOS 8.0, *)
    func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?)
}

  • 最后忘巧,我們只需要在改變系統(tǒng)mode的時(shí)候,重寫代理:
func updateImageView() {
    let image = traitCollection.userInterfaceStyle == .light ? UIImage(named: "dark-ios") : UIImage(named: "white-ios")
    imageView.image = image
}

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    super.traitCollectionDidChange(previousTraitCollection)
    updateImageView()
}
3.1.8.1.3 顏色適配
  • 顏色適配有三種方式:
  • 方法一:是通過Assets.xcassets添加一個(gè)Color Set,目前系統(tǒng)支持≥iOS11.0
extension UIColor {
    @available(iOS 11.0, *)
    public /*not inherited*/ init?(named name: String) // load from main bundle

    @available(iOS 11.0, *)
    public /*not inherited*/ init?(named name: String, in bundle: Bundle?, compatibleWith traitCollection: UITraitCollection?)
}
colorset-darkmode
  • 方法二:代碼創(chuàng)建動(dòng)態(tài)顏色init(dynamicProvider: @escaping (UITraitCollection) -> UIColor)车胡,目前系統(tǒng)支持≥iOS 13.0
// 方法二
let titleColor = UIColor.init(dynamicProvider: { (trait) -> UIColor in
    return trait.userInterfaceStyle == .light ? UIColor.black : UIColor.white
})
btn.setTitleColor(titleColor, for: .normal)
  • 方法三:像圖片一樣檬输,監(jiān)聽模式轉(zhuǎn)變,重寫traitCollectionDidChange(_:)方法,不推薦這種匈棘。
3.1.8.1.4 狀態(tài)欄適配
  • 目前狀態(tài)欄也增加了一種模式丧慈,由之前的兩種,變成了三種, 其中default由之前的黑色內(nèi)容主卫,變成了會(huì)根據(jù)系統(tǒng)模式逃默,自動(dòng)選擇當(dāng)前展示lightContent還是darkContent
public enum UIStatusBarStyle : Int {
    case `default` // Automatically chooses light or dark content based on the user interface style

    @available(iOS 7.0, *)
    case lightContent // Light content, for use on dark backgrounds

    @available(iOS 13.0, *)
    case darkContent // Dark content, for use on light backgrounds
}
  • 我們?cè)谑褂玫臅r(shí)候簇搅,就可以重寫preferredStatusBarStyle的get方法:
override var preferredStatusBarStyle: UIStatusBarStyle{
    get{
        return .lightContent
    }
}

3.1.9 模態(tài)彈出默認(rèn)交互改變

iOS 13 的 presentViewController 默認(rèn)有視差效果完域,模態(tài)出來的界面現(xiàn)在默認(rèn)都下滑返回。 一些頁(yè)面必須要點(diǎn)確認(rèn)才能消失的瘩将,需要適配吟税。如果項(xiàng)目中頁(yè)面高度全部是屏幕尺寸,那么多出來的導(dǎo)航高度會(huì)出現(xiàn)問題鸟蟹。

/*
 Defines the presentation style that will be used for this view controller when it is presented modally. Set this property on the view controller to be presented, not the presenter.
 If this property has been set to UIModalPresentationAutomatic, reading it will always return a concrete presentation style. By default UIViewController resolves UIModalPresentationAutomatic to UIModalPresentationPageSheet, but other system-provided view controllers may resolve UIModalPresentationAutomatic to other concrete presentation styles.
 Defaults to UIModalPresentationAutomatic on iOS starting in iOS 13.0, and UIModalPresentationFullScreen on previous versions. Defaults to UIModalPresentationFullScreen on all other platforms.
 */
@property(nonatomic,assign) UIModalPresentationStyle modalPresentationStyle API_AVAILABLE(ios(3.2));
  • 解決方案:
// Swift
self.modalPresentationStyle = .fullScreen
 
// Objective-C
self.modalPresentationStyle = UIModalPresentationFullScreen;

3.1.10 App啟動(dòng)過程中乌妙,部分View可能無法實(shí)時(shí)獲取到frame

可能是為了優(yōu)化啟動(dòng)速度,App 啟動(dòng)過程中建钥,部分View可能無法實(shí)時(shí)獲取到正確的frame

  • 解決方案
// 只有等執(zhí)行完 UIViewController 的 viewDidAppear 方法以后藤韵,才能獲取到正確的值,在viewDidLoad等地方 frame Size 為 0熊经,例如:
 [[UIApplication sharedApplication] statusBarFrame];

更多關(guān)于IOS的變化參考:iOS13AdaptationTips

<font face="黑體" color=green size=5>少壯不努力泽艘,老大徒悲傷</font>

參考博客:http://www.reibang.com/p/75f34462bd9a

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市镐依,隨后出現(xiàn)的幾起案子匹涮,更是在濱河造成了極大的恐慌,老刑警劉巖槐壳,帶你破解...
    沈念sama閱讀 212,599評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件然低,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡务唐,警方通過查閱死者的電腦和手機(jī)雳攘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,629評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來枫笛,“玉大人吨灭,你說我怎么就攤上這事⌒糖桑” “怎么了喧兄?”我有些...
    開封第一講書人閱讀 158,084評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵无畔,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我吠冤,道長(zhǎng)浑彰,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,708評(píng)論 1 284
  • 正文 為了忘掉前任拯辙,我火速辦了婚禮闸昨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘薄风。我一直安慰自己饵较,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,813評(píng)論 6 386
  • 文/花漫 我一把揭開白布遭赂。 她就那樣靜靜地躺著循诉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪撇他。 梳的紋絲不亂的頭發(fā)上茄猫,一...
    開封第一講書人閱讀 50,021評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音困肩,去河邊找鬼划纽。 笑死,一個(gè)胖子當(dāng)著我的面吹牛锌畸,可吹牛的內(nèi)容都是我干的勇劣。 我是一名探鬼主播,決...
    沈念sama閱讀 39,120評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼潭枣,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼比默!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起盆犁,我...
    開封第一講書人閱讀 37,866評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤命咐,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后谐岁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體醋奠,經(jīng)...
    沈念sama閱讀 44,308評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,633評(píng)論 2 327
  • 正文 我和宋清朗相戀三年伊佃,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了窜司。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,768評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡锭魔,死狀恐怖例证,靈堂內(nèi)的尸體忽然破棺而出路呜,到底是詐尸還是另有隱情迷捧,我是刑警寧澤织咧,帶...
    沈念sama閱讀 34,461評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站漠秋,受9級(jí)特大地震影響笙蒙,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜庆锦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,094評(píng)論 3 317
  • 文/蒙蒙 一捅位、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧搂抒,春花似錦艇搀、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,850評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至芳杏,卻和暖如春矩屁,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背爵赵。 一陣腳步聲響...
    開封第一講書人閱讀 32,082評(píng)論 1 267
  • 我被黑心中介騙來泰國(guó)打工吝秕, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人空幻。 一個(gè)月前我還...
    沈念sama閱讀 46,571評(píng)論 2 362
  • 正文 我出身青樓烁峭,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親秕铛。 傳聞我的和親對(duì)象是個(gè)殘疾皇子则剃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,666評(píng)論 2 350

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