前陣子項目開發忙成狗,就一直沒做iOS11的適配,直到XcodeGM版發布后,我胸有成竹的在iPhoneX上跑起項目,整個人都涼透了...下面總結一下我遇到的坑,不是很全面,日后補充。
導航欄
導航欄高度的變化
iOS11之前導航欄默認高度為64pt(這里高度指statusBar + NavigationBar),iOS11之后如果設置了prefersLargeTitles = YES則為96pt,默認情況下還是64pt,但在iPhoneX上由于劉海的出現statusBar由以前的20pt變成了44pt,所以iPhoneX上高度變為88pt,如果項目里隱藏了導航欄加了自定義按鈕之類的,這里需要注意適配一下。
導航欄圖層及對titleView布局的影響
iOS11之前導航欄的title是添加在UINavigationItemView上面,而navigationBarButton則直接添加在UINavigationBar上面,如果設置了titleView,則titleView也是直接添加在UINavigationBar上面。iOS11之后,大概因為largeTitle的原因,視圖層級發生了變化,如果沒有給titleView賦值,則titleView會直接添加在_UINavigationBarContentView上面,如果賦值了titleView,則會把titleView添加在_UITAMICAdaptorView上,而navigationBarButton被加在了_UIButtonBarStackView上,然后他們都被加在了_UINavigationBarContentView上,如圖:
圖1
所以如果你的項目是自定義的navigationBar,那么在iOS11上運行就可能出現布局錯亂的bug,解決辦法是重寫UINavigationBar的layoutSubviews方法,調整布局,上代碼:
- (void)layoutSubviews {? ? [superlayoutSubviews];//注意導航欄及狀態欄高度適配self.frame =CGRectMake(0,0,CGRectGetWidth(self.frame), naviBarHeight);for(UIView*viewinself.subviews) {if([NSStringFromClass([viewclass]) containsString:@"Background"]) {? ? ? ? ? ? view.frame =self.bounds;? ? ? ? }elseif([NSStringFromClass([viewclass]) containsString:@"ContentView"]) {CGRectframe = view.frame;? ? ? ? ? ? frame.origin.y = statusBarHeight;? ? ? ? ? ? frame.size.height =self.bounds.size.height - frame.origin.y;? ? ? ? ? ? view.frame = frame;? ? ? ? }? ? }}
再補充一點,看了簡書App適配iOS11發現titleView支持autolayout,這要求titleView必須是能夠自撐開的或實現了- intrinsicContentSize方法
- (CGSize)intrinsicContentSize {returnUILayoutFittingExpandedSize;}
繼承自UIScrollView的視圖偏移問題
大家在iOS11設備上運行出現最多問題應該就是tableview莫名奇妙的偏移20pt或者64pt了。。原因是iOS11棄用了automaticallyAdjustsScrollViewInsets屬性,取而代之的是UIScrollView新增了contentInsetAdjustmentBehavior屬性,這一切的罪魁禍首都是新引入的safeArea,關于safeArea適配這篇文章iOS 11 安全區域適配總結講的很詳細,感興趣的可以看下,我直接貼適配代碼,因為低版本直接用contentInsetAdjustmentBehavior會報警告,所有定義了如下的宏(感謝@炒雞范的指正,之前的宏犯了個低級錯誤...現改為)
#define? adjustsScrollViewInsets(scrollView)\do{\_Pragma("clang diagnostic push")\_Pragma("clang diagnostic ignored \"-Warc-performSelector-leaks\"")\if([scrollView respondsToSelector:NSSelectorFromString(@"setContentInsetAdjustmentBehavior:")]) {\NSMethodSignature*signature = [UIScrollViewinstanceMethodSignatureForSelector:@selector(setContentInsetAdjustmentBehavior:)];\NSInvocation*invocation = [NSInvocationinvocationWithMethodSignature:signature];\NSIntegerargument =2;\? ? invocation.target = scrollView;\? ? invocation.selector =@selector(setContentInsetAdjustmentBehavior:);\? ? [invocation setArgument:&argument atIndex:2];\? ? [invocation retainArguments];\? ? [invocation invoke];\}\_Pragma("clang diagnostic pop")\}while(0)
還有的發現某些界面tableView的sectionHeader、sectionFooter高度與設置不符的問題,在iOS11中如果不實現-tableView: viewForHeaderInSection:和-tableView: viewForFooterInSection:,則-tableView: heightForHeaderInSection:和- tableView: heightForFooterInSection:不會被調用,導致它們都變成了默認高度,這是因為tableView在iOS11默認使用Self-Sizing,tableView的estimatedRowHeight、estimatedSectionHeaderHeight、estimatedSectionFooterHeight三個高度估算屬性由默認的0變成了UITableViewAutomaticDimension,解決辦法簡單粗暴,就是在對應界面實現對應方法或把tableView的這三個屬性設為0。如果你想全局關閉Self-Sizing可使用下面這段代碼:
UITableView.appearance.estimatedRowHeight =0;UITableView.appearance.estimatedSectionFooterHeight =0;UITableView.appearance.estimatedSectionHeaderHeight =0;
如果你使用了Masonry,某些界面需要適配需要適配safeArea,請更新到最新版本,可以試試下面這段代碼
if(@available(iOS11.0, *)) {? ? ? ? make.edges.equalTo(self.view.mas_safeArea);? ? }else{? ? ? ? make.edges.equalTo(self.view);? ? }
相冊訪問權限
看其他適配文章上對iOS11相冊權限調整的說明是“iOS11把NSPhotoLibraryUsageDescription替換成了NSPhotoLibraryAddUsageDescription”,奇怪的是我的項目并沒有添加NSPhotoLibraryAddUsageDescription,在訪問相冊時也沒發生crash,后來在仔細閱讀了官方文檔才發現NSPhotoLibraryAddUsageDescription只針對相冊存儲權限,在iOS11上系統默認打開了用戶相冊的訪問權限,如果應用需要存儲權限就需要添加這個key,否則就會crash。
AppIcon
在iOS11上發現了一個奇怪的現象,APP在啟動時圖標會出現黑邊,如圖(處女座實在忍不了...)
圖2
原因是iOS11修改了App啟動動畫,如果你的App圖標有圓角那么就會變成這個鳥樣了...所有圖標都換成直角就好了,具體規范見Human Interface Guidelines-App Icon,還是要聽蘋果爸爸的話啊...
iPhoneX
LaunchImage
關于iPhoneX(我就不吐槽劉海了...),如果你的APP在iPhoneX上運行發現沒有充滿屏幕,上下有黑色區域,那么你應該也像我一樣LaunchImage沒有用storyboard而是用的Assets,解決辦法如圖,啟動圖的尺寸為1125x2436,or you caniOS開發時如何使用 Launch Screen Storyboard。
圖3
TabBarController
如果你使用了原生tabBar,系統會自動適配,因為我們的項目用了第三方的TabBarController,在iPhoneX運行,tabBar看起來怪怪的(如果不確定你的項目tabBar在iPhoneX上看起來是否正常,可以參照模擬器的照片APP,一看便知)...估計作者要等到猴年馬月才適配iPhoneX,項目又著急上線,就自己改了下,主要是tabBar高度及tabBarItem偏移適配,iPhoneX由于底部安全區的原因UITabBar高度由49pt變成了83pt,多出來的34pt是空白手勢區域。可以通過判斷機型來修改相關界面代碼,方式有兩種,通過分辨率判斷:
#define kDevice_Is_iPhoneX ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1125, 2436), [[UIScreen mainScreen] currentMode].size) : NO)
通過設備名稱判斷:
@"iPhone10,1" : @"iPhone 8",
@"iPhone10,4" : @"iPhone 8",
@"iPhone10,2" : @"iPhone 8 Plus",
@"iPhone10,5" : @"iPhone 8 Plus",
@"iPhone10,3" : @"iPhone X",
@"iPhone10,6" : @"iPhone X",
這里推薦使用UIDeviceIdentifier。
目前遇到的就這些坑,歡迎大家指正補充~
作為一名iOS開發人員,想到當年嘲笑Android開發蛋疼的適配各種機型心情如圖...
圖4
后來發現原因是項目的APP圖標有圓角,因為iOS11修改了啟動動畫,導致這一問題直接暴露了...關于AppIcon規范詳見[Human Interface Guidelines
iOS-App Icon](https://developer.apple.com/ios/human-interface-guidelines/icons-and-images/app-icon/)
最后奉上WWDC官方視頻: