随着iOS11正式版的推送和iPhoneX的即将到來,是時候為我們的App做新一輪的适配,下面我來總結下我們項目中遇到的一些問題。
導航欄
導航欄高度的變化
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 {
[super layoutSubviews];
//注意導航欄及狀态欄高度适配
self.frame = CGRectMake(, , CGRectGetWidth(self.frame), naviBarHeight);
for (UIView *view in self.subviews) {
if([NSStringFromClass([view class]) containsString:@"Background"]) {
view.frame = self.bounds;
}
else if ([NSStringFromClass([view class]) containsString:@"ContentView"]) {
CGRect frame = 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 {
return UILayoutFittingExpandedSize;
}
UIScrollView、UITableView、UICollectionView
大家在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 = [UIScrollView instanceMethodSignatureForSelector:@selector(setContentInsetAdjustmentBehavior:)];\
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];\
NSInteger argument = ;\
invocation.target = scrollView;\
invocation.selector = @selector(setContentInsetAdjustmentBehavior:);\
[invocation setArgument:&argument atIndex:];\
[invocation retainArguments];\
[invocation invoke];\
}\
_Pragma("clang diagnostic pop")\
} while ()
還有的發現某些界面
tableView
的
sectionHeader
、
sectionFooter
高度與設定不符的問題,在iOS11中如果不實作
-tableView: viewForHeaderInSection:
和
-tableView: viewForFooterInSection:
,則
-tableView: heightForHeaderInSection:
和
- tableView: heightForFooterInSection:
不會被調用,導緻它們都變成了預設高度,這是因為
tableView
在iOS11預設使用
Self-Sizing
,
tableView
的
estimatedRowHeight
、
estimatedSectionHeaderHeight
、
estimatedSectionFooterHeight
三個高度估算屬性由預設的0變成了
UITableViewAutomaticDimension
,解決辦法簡單粗暴,就是實作對應方法或把這三個屬性設為0。
如果你使用了
Masonry
,那麼你需要适配
safeArea
if (@available(iOS , *)) {
make.edges.equalTo()(self.view.safeAreaInsets)
} else {
make.edges.equalTo()(self.view)
}
iPhoneX
LaunchImage
關于iPhoneX(我就不吐槽劉海了...),如果你的APP在iPhoneX上運作發現沒有充滿螢幕,上下有黑色區域,那麼你應該也像我一樣
LaunchImage
沒有用
storyboard
而是用的
Assets
,解決辦法如圖,啟動圖的尺寸為
1125x2436
,or you can iOS開發時如何使用 Launch Screen Storyboard。
圖2
TabBarController
因為我們的項目用了第三方的
TabBarController
,在iPhoneX運作,tabBar看起來怪怪的...估計作者要等到猴年馬月才适配iPhoneX,項目又着急上線,就自己修改了第三方,主要是
tabBar
高度及
tabBarItem
偏移适配,iPhoneX由于底部安全區的原因
UITabBar
高度由49pt變成了83pt,可以通過判斷機型來修改相關界面代碼,方式有兩種,通過分辨率判斷:
#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。
目前遇到的就這些問題,後續再遇到會繼續補充~