編譯器升級xcode9赖草,準(zhǔn)備適配一下iphoneX的布局漏隐,調(diào)試時發(fā)現(xiàn)由于一些ios11新特性或者底層變化的原因,xcode9運(yùn)行出來的項目界面有bug食店,下面做一下新特性適配和iphoneX布局適配的記錄。
ios11新特性
UIScrollView新特性
- 現(xiàn)象:如上圖所示岖瑰,圖中中間部分是一個表格叛买,在ios11手機(jī)上,表格的頭部多出了一部分空隙蹋订。
- 原因:ios11后率挣,UIScrollView增加了新特性,多了一個屬性:contentInsetAdjustmentBehavior露戒,理解為“調(diào)整內(nèi)邊距的行為”椒功,可選四個參數(shù):
-- UIScrollViewContentInsetAdjustmentAutomatic : 自動調(diào)整;
-- UIScrollViewContentInsetAdjustmentScrollableAxes : 在滾動方向上調(diào)整智什;
-- UIScrollViewContentInsetAdjustmentNever : 從不調(diào)整动漾;
-- UIScrollViewContentInsetAdjustmentAlways : 總是調(diào)整。
默認(rèn)是UIScrollViewContentInsetAdjustmentAutomatic荠锭,所以它自動增加了一部分空隙去避免遮擋(自動調(diào)整的判斷旱眯,包括:是否在導(dǎo)航控制器中、是否在tabbarViewController中等等)。 - 解決方法:
if (@available(iOS 11.0, *))//表示只在ios11以上的版本執(zhí)行
{
_brandTableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}
UISearchBar新特性
-
現(xiàn)象:如圖所示删豺,ios11這個searchBar莫名肥了一圈共虑,我代碼沒變過,同樣設(shè)的是高度44呀页,在ios10上是下面這個樣子
- 原因:UISearchBar的底層結(jié)構(gòu)變了妈拌,簡單來看,以前的UISearchBar是下面這個樣子
簡單來看蓬蝶,它由一個大的紅色view+內(nèi)部輸入框(白色部分)構(gòu)成尘分,在ios11以前,高度設(shè)置控制的是大的紅色view的高度丸氛,內(nèi)部輸入框(白色部分)的高度永遠(yuǎn)固定是28培愁。
而ios11后,它沒了大的紅色view雪位,只有內(nèi)部輸入框(白色部分)竭钝,給高度的時候,自然就控制的是內(nèi)部輸入框(白色部分)的高度雹洗。
所以同樣都是44的高香罐,ios11上的UISearchBar會肥一圈。 - 解決方法:
如果需要跟以前保持同樣的效果时肿,那么在ios11上把UISearchBar的高度設(shè)為28并重新布局
UITableView使用MJRefreshAutoNormalFooter上拉刷新時頁面會跳動
- 現(xiàn)象:正常情況:應(yīng)該是觸發(fā)了上拉刷新庇茫,加載數(shù)據(jù),加載完后增加若干cell螃成,但頁面仍保持在原位置旦签。而軟件在xcode9編譯環(huán)境下的ios11手機(jī)上,加載完后頁面會向上跳一截寸宏,尤其在cell的高度是由model的實際數(shù)據(jù)決定宁炫,尤其在cell高度較大的時候,很明顯氮凝。MJRefresh做了更新羔巢,但實測,還是有問題罩阵。
- 原因:UITableView這兩個代理方法調(diào)用順序變了:cellForRowAtIndexPath和heightForRowAtIndexPath竿秆,直接導(dǎo)致了獲取高度算tableview偏移有問題。
- 解決辦法:
實現(xiàn)以下方法:
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 200;
}
盡量給出較接近實際cell高度的數(shù)值稿壁,跳動問題會消失幽钢。
- 2018.02.01更新,不需要實現(xiàn)estimatedHeightForRowAtIndexPath這個代理傅是,設(shè)置下面三個參數(shù)即可
if (@available(iOS 11.0, *))//表示只在ios11以上的版本執(zhí)行
{
tableview.estimatedRowHeight = 0;
tableview.estimatedSectionHeaderHeight = 0;
tableview.estimatedSectionFooterHeight = 0;
}
導(dǎo)航欄返回按鈕偏移匪燕、自定義按鈕難以點中
- 現(xiàn)象:UINavigationController的navBar的返回按鈕蕾羊,我隱藏了它的文字,結(jié)果它比在ios10上谎懦,明顯向右向下偏移了一截(不隱藏文字時不會有這種問題)肚豺。我自定義了一個左邊按鈕作為返回按鈕,發(fā)現(xiàn)非常難點中界拦。
- 原因:底層實現(xiàn)機(jī)制改變。
- 解決辦法:
自定義左邊按鈕作為返回按鈕
那么如何解決自定義按鈕難以點中的問題呢梗劫?
給navBar添加一個單擊手勢享甸,判斷手勢位置,如果在左邊某個范圍梳侨,就調(diào)用按鈕的點擊事件蛉威。
我是給UIViewController寫了一個分類UIViewController+YYBackBarButton,這樣需要用的頁面里走哺,只需要在viewDidLoad中加下面一句話就行了
[self addCustomBackButtonWithBackButtonColor:UIColorFromRGB(0x979797)];
分類.m文件代碼如下:
#import "UIViewController+YYBackBarButton.h"
#import "UIImage+extend.h"
@implementation UIViewController (YYBackBarButton)
- (void)addCustomBackButtonWithBackButtonColor:(UIColor *)backButtonColor
{
self.navigationController.navigationBar.tintColor = [UIColor clearColor];//返回按鈕顏色
self.navigationController.navigationBar.backItem.hidesBackButton = YES;//隱藏返回按鈕
self.navigationController.interactivePopGestureRecognizer.delegate = (id)self;//開啟手勢右滑返回
//創(chuàng)建返回按鈕
UIButton *backButton = [[UIButton alloc] init];
backButton.frame = CGRectMake(0, 0, 13, 22);
[backButton setImage:[[UIImage imageNamed:@"backButton.png"] imageWithColor:backButtonColor] forState:UIControlStateNormal];//imageWithColor這個方法是UIImage+extend分類里的方法蚯嫌,作用是對圖片的顏色進(jìn)行自定義渲染(說白了就是改圖片顏色)
backButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
//返回按鈕偏移值,根據(jù)自己的需要設(shè)置偏移丙躏,已達(dá)到想要的UI效果
CGFloat insetNumber = 0;
if (@available(iOS 11.0, *))
{
if (kMainScreenHeight == IPHONE_4_SCREEN_HEIGHT) insetNumber = 8;
else if (kMainScreenHeight == IPHONE_5_SCREEN_HEIGHT) insetNumber = 8;
else if (kMainScreenHeight == IPHONE_6_SCREEN_HEIGHT) insetNumber = 8;
else if (kMainScreenHeight == IPHONE_6PLUS_SCREEN_HEIGHT) insetNumber = 12;
else if (kMainScreenHeight == IPHONE_X_SCREEN_HEIGHT) insetNumber = 8;
}
else
{
if (kMainScreenHeight == IPHONE_4_SCREEN_HEIGHT) insetNumber = 8;
else if (kMainScreenHeight == IPHONE_5_SCREEN_HEIGHT) insetNumber = 8;
else if (kMainScreenHeight == IPHONE_6_SCREEN_HEIGHT) insetNumber = 8;
else if (kMainScreenHeight == IPHONE_6PLUS_SCREEN_HEIGHT) insetNumber = 12;
else if (kMainScreenHeight == IPHONE_X_SCREEN_HEIGHT) insetNumber = 8;
}
[backButton setImageEdgeInsets:UIEdgeInsetsMake(0, -insetNumber, 0, insetNumber)];
//添加按鈕事件
[backButton addTarget:self action:@selector(customClickBackButton) forControlEvents:UIControlEventTouchUpInside];
//添加手勢择示,獲取點擊,避免不容易點中返回按鈕的問題
[self.navigationController.navigationBar addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(clickNavBar:)]];
//把按鈕設(shè)置為導(dǎo)航欄左邊按鈕
UIBarButtonItem *leftBarButtonItem = [[UIBarButtonItem alloc]initWithCustomView:backButton];
self.navigationItem.leftBarButtonItem = leftBarButtonItem;
}
- (void)customClickBackButton
{
[self.navigationController popViewControllerAnimated:YES];
}
- (void)clickNavBar:(UITapGestureRecognizer *)tap
{
//獲取手勢的點
CGPoint tapPoint = [tap locationInView:self.navigationController.navigationBar];
if (tapPoint.x <= kMainScreenWidth * 0.15)//如果手勢的點在左邊15%晒旅,就讓它出發(fā)返回按鈕事件
{
[self customClickBackButton];
}
}
@end
其中有個圖片重新渲染顏色的方法栅盲,我寫在了UIImage+extend這個分類中,可以改一張圖片的整體顏色废恋,方法實現(xiàn)如下:
- (UIImage *)imageWithColor:(UIColor *)color
{
UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, 0, self.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextSetBlendMode(context, kCGBlendModeNormal);
CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);
CGContextClipToMask(context, rect, self.CGImage);
[color setFill];
CGContextFillRect(context, rect);
UIImage*newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
這樣處理之后的效果谈秫,就跟以前一樣了:
鍵盤新特性
- 現(xiàn)象:我在項目里使用IQKeyboardManager框架,正常情況下鱼鼓,紅圈處左邊應(yīng)該有上下跳轉(zhuǎn)輸入框的按鈕拟烫、右邊應(yīng)該有完成按鈕。
- 原因:ios11鍵盤window底層布局變化迄本。
-
解決辦法:
更新IQKeyboardManager框架(研究了半天原因才發(fā)現(xiàn)人家已經(jīng)更新了做好適配了)硕淑。
XCode9運(yùn)行訪問系統(tǒng)相冊崩潰問題
- 現(xiàn)象:如圖保存圖片功能,在XCode9下運(yùn)行會崩潰
- 原因:info.plist新增了權(quán)限配置
-
解決:info.plist新增一條權(quán)限:Privacy - Photo Library Additions Usage Description
iphoneX適配
主要是UI方面的適配岸梨,但也發(fā)現(xiàn)了一個不明原因的bug喜颁。
bug的解決
- 現(xiàn)象:注意觀察上圖中tabbar的位置。從帶tabbar的控制器push到其它控制器(hidesBottomBarWhenPushed = YES)曹阔,tabbar在push的時候會突然向上移動一截半开,但是pop的時候又是正常的,并且同樣是ios11的iphone8上都是正常的赃份。
- 原因:目前不清楚是不是xcode9模擬器的問題寂拆,也不知道真機(jī)上會不會有奢米。
- 解決:重寫- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated方法,自己控制push時tabbar的frame
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
// 重寫super
[super pushViewController:viewController animated:animated];
// 修改tabBra的frame
if (isIPhoneX)//解決push時tabbar瞬間上移的問題
{
CGRect frame = self.tabBarController.tabBar.frame;
frame.origin.y = [UIScreen mainScreen].bounds.size.height - frame.size.height;
self.tabBarController.tabBar.frame = frame;
}
}
即可恢復(fù)正常狀態(tài)纠永。
UI適配
主要是statusBar(頂部狀態(tài)欄)的高度不一樣了鬓长、底部增加了一個安全距離。適配思路就是避開這些地方尝江,具體思路下文分開介紹涉波。
頂部狀態(tài)欄的問題
- 現(xiàn)象:如圖所示,頂部的searchView被擋住了一塊炭序。
- 原因:這個頁面的頂部白色部分是一個view啤覆,它的高度我寫死為64(普通手機(jī)里導(dǎo)航欄+狀態(tài)欄整體高度),所以在普通手機(jī)里看起就是一個正常的導(dǎo)航欄惭聂,而在這里就發(fā)生了遮擋窗声,因為普通手機(jī)的狀態(tài)欄高度是20,而iphoneX是44辜纲。
- 解決:所有這種頂部的view笨觅,都不應(yīng)該寫死64的高度,而應(yīng)該寫成導(dǎo)航欄高度+狀態(tài)欄高度耕腾。
導(dǎo)航欄高度所有都是44见剩,沒有變化,而狀態(tài)欄高度分為20和44幽邓,布局時判斷一下是不是iphoneX炮温,數(shù)值也隨之變化,最好是寫成宏牵舵。
底部安全距離的問題
- 現(xiàn)象:如上圖所示柒啤,tabbar的高度明顯比普通手機(jī)里高得多,增加的區(qū)域大概是下圖紅圈的區(qū)域:
這部分的高度畸颅,即底部安全距離的高度是34
總所周知担巩,底部出現(xiàn)安全距離,是為了給系統(tǒng)的手勢讓路没炒,用戶在底部黑條附近進(jìn)行拖動時涛癌,可以達(dá)到原來home鍵的效果。
然而送火,通過我在模擬器上的反復(fù)實驗拳话,系統(tǒng)手勢的觸發(fā)范圍,并沒有34這么高种吸,而是從黑條頂部到屏幕底部這個范圍弃衍,這部分的高度,以下稱作系統(tǒng)手勢有效范圍坚俗,高度為13镜盯。 -
實際問題:上圖是系統(tǒng)處理的tabbar高度岸裙。在自己寫的頁面里,就會出現(xiàn)遮擋的問題:
-
解決:底部兩個按鈕背后有個白色view速缆,它的高度是寫死為54降允,應(yīng)該改為54+手勢有效范圍高度,手勢有效范圍高度根據(jù)是不是iphoneX賦值為13或0艺糜,這樣就完美適配了iphoneX和普通手機(jī)剧董,解決效果如下:
備注
1、干貨分享:對于手機(jī)型號的判斷倦踢、底部高度送滞、頂部高度等,我都寫成了宏辱挥,需要的朋友拿走不謝:
//是否是手機(jī)
#define isIPhone (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
//是否是iphoneX
#define isIPhoneX (kMainScreenWidth >= 375.0f && kMainScreenHeight >= 812.0f && isIPhone)
//蘋果X寬高
#define IPHONE_X_SCREEN_WIDTH 375
#define IPHONE_X_SCREEN_HEIGHT 812
//底部安全高度
#define BOTTOM_SAFE_HEIGHT (isIPhoneX ? 34 : 0)
//系統(tǒng)手勢高度
#define SYSTEM_GESTURE_HEIGHT (isIPhoneX ? 13 : 0)
//tabbar高度
#define TABBAR_HEIGHT (49 + BOTTOM_SAFE_HEIGHT)
//狀態(tài)欄高度
#define STATUS_HEIGHT (isIPhoneX ? 44 : 20)
//導(dǎo)航欄高
#define NAVBAR_HEIGHT 44