iOS 11和iPhone X適配

iOS 11和iPhone X相較于之前的系統(tǒng)和手機(jī)都有了很大的變化,特別是iPhone X在UI上的變化。在iOS 11發(fā)布后,更新系統(tǒng)看了下App,果然是很多地方都存在著異常和Bug,下面針對(duì)已經(jīng)了解和出現(xiàn)的問題進(jìn)行適配說明。

一、iPhone X適配

1、SafeArea

iOS 11之后廢棄了iOS 7在UIViewController中引入的topLayoutGuide和bottomLayoutGuide,開始引入了一個(gè)新的布局概念:SafeArea,它被用來描述視圖中不可被任何內(nèi)容遮擋的區(qū)域。只要我們的UI元素布局在了SafeArea內(nèi),就能避免被NavigationBar、TabBar、StatusBar等等一些bar的遮擋。

iPhone X的安全區(qū)域在默認(rèn)情況下:

  • 豎屏 frame : {0, 44, ScreenWidth, ScreenHeight - 44 - 34}
  • 橫屏 frame : {44, 0, ScreenWith - 44 - 44, ScreenHeight - 21}

具體顯示如下圖藍(lán)框frame所示:

iPhoneX_SafeArea_portrait
iPhone X_SafeArea_landscape

非iPhone X的話,安全區(qū)域在默認(rèn)情況下:

  • 豎屏 frame : {0, 20, ScreenWidth, ScreenHeight - 20}
  • 橫屏 frame : {0, 0, ScreenWith, ScreenHeight}

App的布局應(yīng)該在填滿整個(gè)顯示屏的同時(shí)保證內(nèi)容和控件的正確顯示,并且便于點(diǎn)按。我們App的內(nèi)容元素和按鈕要放在SafeArea內(nèi),以避開屏幕角落和傳感器槽,讓其在填滿屏幕的同時(shí)而不被切割而顯示不完整。在橫屏模式中,我們更要注意內(nèi)容和按鈕的布局,如下圖所示。

iPhone X橫屏模式布局

2、iPhone X

iPhone X最大的變化是屏幕,屏幕采用了高分辨率的圓角全面屏,屏幕尺寸為1125px × 2436px(375pt × 812pt @3x),狀態(tài)欄和頂部tabBar的高度也發(fā)生了變化。

這些變化造成了以下幾個(gè)問題:

2.1、啟動(dòng)iPhone X后屏幕沒鋪滿(上下各有一截黑條)

iPhone X屏幕沒鋪滿
  • 問題原因:項(xiàng)目使用Launch Images Sourc作為啟動(dòng)方式,缺少iPhone X的啟動(dòng)圖
  • 解決方案:
    方案一:準(zhǔn)備一張1125px × 2436px的啟動(dòng)圖放到項(xiàng)目的LaunchImage里邊
    方案二:通過LaunchScreen.storyboard方式啟動(dòng)

2.2、控制器的view大小計(jì)算錯(cuò)誤

  • 問題原因:iPhone X的StatusBar和底部TabBar高度都發(fā)生了變化,如果項(xiàng)目中之前計(jì)算view的frame時(shí)寫死了高度(StatusBar : 20, TabBar : 49)的話,就會(huì)出現(xiàn)view計(jì)算出來的frame存在問題。
  • 解決方案:抽取出幾個(gè)宏定義來表示StatusBar和TabBar的高度,使用起來也會(huì)非常方便,之后如果再出現(xiàn)改變,變動(dòng)起來也比較靈活。
#define XXStatusBarHeight [[UIApplication sharedApplication] statusBarFrame].size.height
#define XXNavBarHeight 44.0
#define XXTabBarHeight (XXStatusBarHeight > 20 ? 83 : 49)
#define XXCustomTabBarHeight 49
#define XXTopHeight (XXStatusBarHeight + XXNavBarHeight)

二、iOS 11適配

1、UIScrollView和UITableView新屬性

iOS 11之后,UIViewController的automaticallyAdjustsScrollViewInsets屬性被廢棄了,這個(gè)屬性的作用就是根據(jù)所在界面的StatusBar、NavigationBar和TabBar的高度,自動(dòng)的去調(diào)整UIScrollView的Insets,默認(rèn)為YES。如果設(shè)置為NO,就是由我們自己來修改布局,不讓它自動(dòng)調(diào)整。官方文檔建議我們使用contentInsetAdjustmentBehavior來代替它,這是一個(gè)枚舉屬性,定義如下:

typedef NS_ENUM(NSInteger, UIScrollViewContentInsetAdjustmentBehavior) {
    UIScrollViewContentInsetAdjustmentAutomatic, // Similar to .scrollableAxes, but for backward compatibility will also adjust the top & bottom contentInset when the scroll view is owned by a view controller with automaticallyAdjustsScrollViewInsets = YES inside a navigation controller, regardless of whether the scroll view is scrollable
    UIScrollViewContentInsetAdjustmentScrollableAxes, // Edges for scrollable axes are adjusted (i.e., contentSize.width/height > frame.size.width/height or alwaysBounceHorizontal/Vertical = YES)
    UIScrollViewContentInsetAdjustmentNever, // contentInset is not adjusted
    UIScrollViewContentInsetAdjustmentAlways, // contentInset is always adjusted by the scroll view's safeAreaInsets
} API_AVAILABLE(ios(11.0),tvos(11.0));

// 通過上面的枚舉,配置 adjustedContentInset 的行為
@property(nonatomic) UIScrollViewContentInsetAdjustmentBehavior contentInsetAdjustmentBehavior;
// 如果 contentInsetAdjustmentBehavior 允許,此屬性可以整合 safeAreaInsets 來描述安全區(qū)域
@property(nonatomic, readonly) UIEdgeInsets adjustedContentInset;
// 改變 adjustedContentInset 的 response 和 delegate
- (void)adjustedContentInsetDidChange;
- (void)scrollViewDidChangeAdjustedContentInset:(UIScrollView *)scrollView;
// 用于描述未經(jīng)轉(zhuǎn)換的 content area 區(qū)域
@property(nonatomic,readonly,strong) UILayoutGuide *contentLayoutGuide;
// 用于描述未經(jīng)轉(zhuǎn)換的 scroll view 的 frame
@property(nonatomic,readonly,strong) UILayoutGuide *frameLayoutGuide;

這個(gè)contentInsetAdjustmentBehavior屬性是用來配置UIScrollView和UITableView的adjustedContentInset的行為的,adjustedContentInset也是iOS 11新增的一個(gè)屬性。當(dāng)contentInsetAdjustmentBehavior允許時(shí),adjustedContentInset這個(gè)屬性替代了contentInset所描述的區(qū)域,并且整合了safeAreaInsets來描述安全區(qū)域。adjustedContentInset表示contentView.frame.origin偏移了scrollView.frame.origin多少。

adjustedContentInset和contentInset

2、iOS 11

上面所說的iOS 11變化還有其他一些變化,也帶來了一些問題,需要我們?nèi)プ鲞m配。

2.1、UITableView或UIScrollView內(nèi)容發(fā)生向下偏移

  • 問題原因: automaticallyAdjustsScrollViewInsets屬性被廢棄后,當(dāng)tableview或scrollview超出安全區(qū)域時(shí),系統(tǒng)自動(dòng)調(diào)整了SafeAreaInsets的值,進(jìn)而影響了adjustedContentInset的值,最終導(dǎo)致tableview或scrollview的內(nèi)容到邊緣的距離發(fā)生了變化,導(dǎo)致內(nèi)容發(fā)生了偏移。
  • 解決方案:將contentInsetAdjustmentBehavior屬性置為UIScrollViewContentInsetAdjustmentNever。
if (@available(iOS 11.0, *)) {
    _tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}

2.2、導(dǎo)航欄返回時(shí)View出現(xiàn)下沉現(xiàn)象

導(dǎo)航欄在返回到上一頁(yè)時(shí),上一頁(yè)的View出現(xiàn)了下沉現(xiàn)象,返回的整個(gè)過程中由下往上浮動(dòng)上來。

導(dǎo)航欄返回時(shí)View出現(xiàn)下沉現(xiàn)象
  • 問題原因:這是因?yàn)閁IScrollView的contentInsetAdjustmentBehavior屬性默認(rèn)為UIScrollViewContentInsetAdjustmentAutomatic,會(huì)對(duì)視圖內(nèi)容的位置做出自動(dòng)計(jì)算和調(diào)整。
  • 解決方案:解決方法同上面一致,將UIScrollView的contentInsetAdjustmentBehavior屬性置為UIScrollViewContentInsetAdjustmentNever。
if (@available(iOS 11.0, *)) {
    _scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}

2.3、UITableView的Header、Footer、cell高度出現(xiàn)問題,上拉刷新cell發(fā)生跳動(dòng)

  • 問題原因:UITableView在iOS 11中的明顯改變就是默認(rèn)開啟Self-Sizing,從iOS 8引入Self-Sizing后,可以通過實(shí)現(xiàn)estimatedRowHeight屬性來展示動(dòng)態(tài)的內(nèi)容,但在iOS 11之前都是默認(rèn)關(guān)閉的。當(dāng)開啟時(shí),UITableView的Header,F(xiàn)ooter和cell的高度由原來關(guān)閉時(shí)的0變?yōu)閁ITableViewAutomaticDimension。
  • 解決方案:如果項(xiàng)目中沒有用到estimatedRowHeight,但是仍然想使用Self-Sizing關(guān)閉時(shí)的效果,可以使用下面的代碼將Self-Sizing關(guān)閉。
_tableView.estimatedRowHeight = 0;
_tableView.estimatedSectionHeaderHeight = 0;
_tableView.estimatedSectionFooterHeight = 0;

如果不想開啟Self-Sizing效果,或者UITableView的Header、Footer、cell高度出現(xiàn)問題,可以在Appdelegate里邊全局設(shè)置上面提到的這些屬性,能夠避免在單個(gè)類文件中每次都要添加這些代碼所帶來的麻煩,代碼如下:

if (@available(iOS 11.0, *)) {
    [UIScrollView appearance].contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
    [UITableView appearance].estimatedRowHeight = 0;
    [UITableView appearance].estimatedSectionHeaderHeight = 0;
    [UITableView appearance].estimatedSectionFooterHeight = 0;
}

2.4、導(dǎo)航欄的左右UIBarButtonItem的UI位置調(diào)整失效

  • 問題原因iOS 11之前采用UIBarButtonSystemItemFixedSpace的方式可以對(duì)UIBarButtonItem做一個(gè)位置調(diào)整,但是這種方法在iOS 11已經(jīng)失效,代碼如下所示
UIButton *allBtn = [UIButton buttonWithType:UIButtonTypeCustom];
UIBarButtonItem *rightBarItem = [[UIBarButtonItem alloc] initWithCustomView:allBtn];
UIBarButtonItem *negativeSpacer1 = [[UIBarButtonItem alloc]
                                    initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace
                                    target:nil action:nil];
negativeSpacer1.width = -22;
self.navigationItem.rightBarButtonItems = @[negativeSpacer1,rightBarItem];

并且UINavigationBar的層級(jí)關(guān)系也發(fā)生了變化,如圖所示,上面的是iOS 11之前的NavigationBar層級(jí)關(guān)系,下邊的是iOS 11之后的層級(jí)關(guān)系。iOS 11之后UIBarButtonItem都被放在了_UINavigationBarContentView--> _UIButtonBarStackView--> _UITAMICAdaptorView中了。

iOS 11之前的NavigationBar層級(jí)關(guān)系
iOS 11之后的NavigationBar層級(jí)關(guān)系
  • 解決方案:目前沒有找到特別完美的解決方案,臨時(shí)替代方案是,設(shè)置自定義Button的contentHorizontalAlignment屬性,讓Button的內(nèi)容分貝根據(jù)leftBarButtonItem,rightBarButtonItem而左對(duì)齊和右對(duì)齊,從而達(dá)到和之前相似的效果。
if (IOS11) leftButton.contentHorizontalAlignment =  UIControlContentHorizontalAlignmentLeft;
if (IOS11) rightButton.contentHorizontalAlignment =  UIControlContentHorizontalAlignmentRight;

2.5、相冊(cè)權(quán)限獲取

在iOS 11之前,我們需要在info.plist中添加Privacy - Photo Library Usage Description,用戶在訪問相冊(cè)(包括讀和寫權(quán)限)的時(shí)候,才能夠彈出授權(quán)。iOS 11之后:

  • Privacy - Photo Library Usage Description無(wú)需添加,默認(rèn)就賦予用戶了相冊(cè)的讀權(quán)限,但是為了適配iOS 11之前的系統(tǒng),還是需要添加在項(xiàng)目中。
  • Privacy - Photo Library Additions Usage DescriptioniOS 11系統(tǒng),在info.plist中添加上這個(gè)property,才能彈出授權(quán)拿到寫權(quán)限來給相冊(cè)添加內(nèi)容。

2.6、AppIcon變化

iOS 11后,Assets.xcassets的AppIcon中增加了App Store圖標(biāo)這一項(xiàng),需要拖入一張1024×1024的Logo圖。

AppIcon_App_Store

參考

iOS 11適配視頻
iPhone X官方適配文檔

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評(píng)論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,556評(píng)論 3 418
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,463評(píng)論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,009評(píng)論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,778評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,218評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,436評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,969評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,795評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,993評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,229評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,659評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,917評(píng)論 1 286
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,687評(píng)論 3 392
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,990評(píng)論 2 374

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