一.iPhone X尺寸問(wèn)題?
1. 高度增加了145pt,變成812pt.?
2.屏幕圓角顯示,注意至少留10pt邊距。
3. 狀態(tài)欄高度由20pt變成44pt,留意這個(gè)距離就能避開(kāi)“劉海”的尷尬,相應(yīng)的導(dǎo)航欄以上變化64--->88。?
4.底部工具欄需要為home indicator留出34pt邊距。 5.物理分辨率為1125px * 2436px
非iPhone X :
StatusBar高20px,NavigationBar高44px,底部TabBar高49px
iPhone X:
StatusBar高44px,NavigationBar高44px,底部TabBar高83px
二.適配用到的宏
// status bar height.
#define? kStatusBarHeight? ? ? (IS_iPhoneX ? 44.f : 20.f)
// Navigation bar height.
#define? kNavigationBarHeight? 44.f
// Tabbar height.
#define? kTabbarHeight? ? ? ? (IS_iPhoneX ? (49.f+34.f) : 49.f)
// Tabbar safe bottom margin.
#define? kTabbarSafeBottomMargin? ? ? ? (IS_iPhoneX ? 34.f : 0.f)
// Status bar & navigation bar height.
#define? kStatusBarAndNavigationBarHeight? (IS_iPhoneX ? 88.f : 64.f)
//判斷是否iPhone X
#define IS_iPhoneX ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1125, 2436), [[UIScreen mainScreen] currentMode].size) : NO)
三.APP啟動(dòng)樣式適配,屏幕未充滿
1.啟動(dòng)頁(yè)屏幕未充滿
APP在iPhone X上占滿整個(gè)屏幕, 而是保持著原有的高度 在屏幕中心位置, 屏幕的頂部和底部都有黑邊.


通過(guò)LaunchScreen.storyboard方式啟動(dòng)
如果使用的是Assets中的LaunchImage, 在增加了iPhone X尺寸的圖片配置后.
LaunchScreen.storyboard方式不用多說(shuō), 這里說(shuō)一下如何在LaunchImage中增加iPhone X尺寸的圖片配置.
方法一:
準(zhǔn)備一張尺寸:1125 * 2436的 3x啟動(dòng)圖片, 移動(dòng)到LaunchImage的Finder目錄中, 并在LaunchImage中的Contents.json文件中增加 (注意Json格式):
{
"extent" : "full-screen",
"idiom" : "iphone",
"subtype" : "2436h",
"filename" : "圖片名.png",
"minimum-system-version" : "11.0",
"orientation" : "portrait",
"scale" : "3x"
}

方法二:





2.引導(dǎo)頁(yè)iPhone X圖片變形


由于iPhone X高度發(fā)生變化,圖片鋪滿整個(gè)屏幕時(shí)候造成圖片拉伸,現(xiàn)在需要UI切一個(gè)1125*2436的3x圖片和以前做iPhone X機(jī)型判斷1124*2001圖片,并且對(duì)圖片contentMode屬性進(jìn)行設(shè)置
if (IS_iPhoneX) {
coverImageNames = [NSArray arrayWithObjects:@"img_big_1_ipx.jpg", @"img_big_2_ipx.jpg",@"img_big_3_ipx.jpg", @"img_big_4_ipx.jpg",nil];
}else{
coverImageNames = [NSArray arrayWithObjects:@"img_big_1.jpg", @"img_big_2.jpg",@"img_big_3.jpg", @"img_big_4.jpg",nil];
}
imageView.clipsToBounds = YES;//超出區(qū)域裁剪
imageView.contentMode = UIViewContentModeScaleAspectFill;//圖片等比例拉伸,會(huì)填充整個(gè)區(qū)域,但是會(huì)有一部分過(guò)大而超出整個(gè)區(qū)域
四:UITableview UICollectionView MJRefresh下拉刷新錯(cuò)亂

iOS11表格用MJRefresh框架下拉刷新的時(shí)候界面會(huì)閃,顯示紊亂,
原因是iOS11棄用了automaticallyAdjustsScrollViewInsets屬性,新增contentInsetAdjustmentBehavior來(lái)替代它
tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
解決方法:MJRefresh作者已經(jīng)針對(duì)iOS 11和iPhone X做了適配,把MJRefresh更新最新的版本
//聲明tableView的位置 添加下面代碼
if (@available(iOS 11.0, *)) {
_tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
_tableView.contentInset = UIEdgeInsetsMake(64, 0, 49, 0);
_tableView.scrollIndicatorInsets = _tableView.contentInset;
}
五.純代碼適配齊劉海
iPhone X導(dǎo)航欄由以前的固定64變成現(xiàn)在88,Statebar的高度由20變成44,增加24,項(xiàng)目中以前用導(dǎo)航欄64地方都進(jìn)行是否iPhoneX判斷,用到宏#define? kStatusBarAndNavigationBarHeight? (IS_iPhoneX ? 88.f : 64.f)
項(xiàng)目中導(dǎo)航欄自定義導(dǎo)航欄會(huì)遇到很多奇葩的問(wèn)題如下圖

(1)在iPhone X中導(dǎo)航欄高度變成88,項(xiàng)目中自定義導(dǎo)航欄高度64,需要對(duì)導(dǎo)航欄高度進(jìn)行判斷
_navigationBar = [[MCCustomNavigationBar alloc]initWithFrame:CGRectMake(0, 0, SCREENW, 64) andType:CustomBarType_Home];
_navigationBar = [[MCCustomNavigationBar alloc]initWithFrame:CGRectMake(0, 0, SCREENW, kStatusBarAndNavigationBarHeight) andType:CustomBarType_Home];
(2)搜索框和左右兩邊按鈕高度有問(wèn)題,因?yàn)閕Phone X中狀態(tài)欄高度由20增加24變成44,所以搜索框和左右兩邊按鈕高度在iPhone X上距頂部高度加上24高度,
#define itemTopOffset (IS_iPhoneX ? (26+24) : 26)
[self.leftBtn mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.offset(itemHorOffset);
make.height.equalTo(@(itemHeight));
make.width.equalTo(@(itemHeight));
make.top.offset(itemTopOffset);
}];
(3)iOS11上searchBar高度明顯變大,

系統(tǒng)的searchBar
UISearchBar的中子控件及其布局
UIView(直接子控件) frame 等于 searchBar的bounds,view的子控件及其布局
UISearchBarBackground(間接子控件) frame 等于searchBar的bounds
UISearchBarTextField(間接子控件) frame.origin等于(8.0, 6.0),即不等于searchBar的bounds
改變searchBar的frame只會(huì)影響其中搜索框的寬度,不會(huì)影響其高度,原因如下:
系統(tǒng)searchBar中的UISearchBarTextField的高度默認(rèn)固定為28
左右邊距固定為8,上下邊距是父控件view的高度減去28除以2
改變UISearchBar的高度
方案
重寫(xiě)UISearchBar的子類(MCSearchBar),重新布局UISearchBar子控件的布局
增加成員屬性contentInset,控制UISearchBarTextField距離父控件的邊距
若用戶沒(méi)有設(shè)置contentInset,則計(jì)算出默認(rèn)的contentInset
若用戶設(shè)置了contentInset,則根據(jù)最新的contentInset布局UISearchBarTextField
新建UISearchBar的子類,增加成員屬性contentInset,用來(lái)調(diào)整UISearchBarTextField距離父控件的邊距。contentInset的setter方法
#pragma mark - setter method
- (void)setContentInset:(UIEdgeInsets)contentInset {
_contentInset.top = contentInset.top;
_contentInset.bottom = contentInset.bottom;
_contentInset.left = contentInset.left;
_contentInset.right = contentInset.right;
self.isChangeFrame = YES;
[self layoutSubviews];
}
- (void)layoutSubviews {
[super layoutSubviews];
for (UIView *subView in self.subviews[0].subviews) {
if ([subView isKindOfClass:[UIImageView class]]) {
//移除UISearchBarBackground
[subView removeFromSuperview];
}
if ([subView isKindOfClass:[UITextField class]]) {
CGFloat height = self.bounds.size.height;
CGFloat width = self.bounds.size.width;
if (_isChangeFrame) {
//說(shuō)明contentInset已經(jīng)被賦值
// 根據(jù)contentInset改變UISearchBarTextField的布局
subView.frame = CGRectMake(_contentInset.left, _contentInset.top, width - 2 * _contentInset.left, height - 2 * _contentInset.top);
} else {
// contentSet未被賦值
// 設(shè)置UISearchBar中UISearchBarTextField的默認(rèn)邊距
CGFloat top = (height - 28.0) / 2.0;
CGFloat bottom = top;
CGFloat left = 8.0;
CGFloat right = left;
_contentInset = UIEdgeInsetsMake(top, left, bottom, right);
subView.frame = CGRectMake(_contentInset.left, _contentInset.top, width - 2 * _contentInset.left, height - 2 * _contentInset.top);
}
}
}
}
在項(xiàng)目中使用自定義的MCSearchBar,SearchBar的高度可以改變
(4)iOS11中UISearchBar沒(méi)有居中居左顯示,并且icon和placeholder間距太窄

現(xiàn)在實(shí)現(xiàn)居中顯示

@property(nonatomic,assign)CGFloatwidth;
//判斷版本
if(@available(iOS11.0, *)){
UITextField *textField = [self.searchBar valueForKey:@"searchField"];
[textField sizeToFit];
//記錄一下這個(gè)時(shí)候的寬度
_width= textField.frame.size.width;
[_searchBar setPositionAdjustment:UIOffsetMake((_searchBar.width-_width)/2.0,0)forSearchBarIcon:UISearchBarIconSearch];
}
然后在代理方法 searchBarTextDidBeginEditing:(UISearchBar*)searchBar 調(diào)整位置
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar{
if (@available(iOS 11.0, *)) {
if(!_searchBar.text.length) {
[_searchBar setPositionAdjustment:UIOffsetMake(0,0)forSearchBarIcon:UISearchBarIconSearch];
}
}
}
結(jié)束的方法? searchBarTextDidEndEditing:(UISearchBar*)searchBar 判斷是否有內(nèi)容
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar{
if (@available(iOS 11.0, *)) {
if(!_searchBar.text.length) {
[_searchBar setPositionAdjustment:UIOffsetMake((_searchBar.width-self.width)/2.0,0) forSearchBarIcon:UISearchBarIconSearch];
}
}
}
如果有占位文字后臺(tái)返的,UITextField在搜索框默認(rèn)文字大小17,可以根據(jù)文字個(gè)數(shù)和大小算出占位文字寬度,然后算出搜索圖標(biāo)的偏移量.

(5)搜索頁(yè)面導(dǎo)航欄中搜索框距離返回按鈕太近

self.searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, testView.width - (SCREENW > 320 ? 90: 100)*SCREEN_Proportion, testView.height)];
由于搜索框距離左邊距離導(dǎo)致的,現(xiàn)在需要定義一個(gè)宏做判斷
#define marginLeft (IS_iPhoneX ? 10 : 0)
self.searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(marginLeft, 0, testView.width - (SCREENW > 320 ? 90: 100)*SCREEN_Proportion, testView.height)];

六.純代碼適配底部工具欄
在iPhone X中底部工具欄需要為home indicator留出34pt邊距,iPhone X以前機(jī)型TarBar高度49,iPhone X中Tarbar高度加上34變成83.由于項(xiàng)目中Tabbar是用自定義的,需要對(duì)Tabbar的高度做適配,用到宏#define kTabbarHeight (IS_iPhoneX ? (49.f+34.f) : 49.f)

適配前代碼
_customBarView = [[UIView alloc] initWithFrame:CGRectMake(0, SCREENH - 49,SCREENW, 49)];
適配后的代碼_customBarView = [[UIView alloc] initWithFrame:CGRectMake(0, SCREENH - kTabbarHeight,SCREENW, kTabbarHeight)];

圖標(biāo)和文字和其他機(jī)型相比偏下,現(xiàn)在需要對(duì)圖標(biāo)和文字高度進(jìn)行調(diào)整,做iPhone X和非iPhone X機(jī)型適配


七.底部view出現(xiàn)問(wèn)題
(1)購(gòu)物車View適配,涉及頁(yè)面商品詳情頁(yè),搜索頁(yè)面,購(gòu)物車頁(yè)面








-(void)updateUIFrame
{
if (_fromType == ToShoppingTrolleyType_New_Other) {
[[MCNavigationLeftView shareManager] initWithTitle:nil andNavi:self andSEL:@selector(back)];
[[MCTabbarTool shareManager]hideTabbarView:NO];
self.view.frame = CGRectMake(0, 0, SCREENW, SCREENH-kStatusBarAndNavigationBarHeight-(IS_iPhoneX?34:0));
}else{
[[MCTabbarTool shareManager]showTabbarView:YES];
self.view.frame = CGRectMake(0, 0, SCREENW, SCREENH-kStatusBarAndNavigationBarHeight-kTabbarHeight);
}
self.cartBottomView.frame = CGRectMake(0, self.view.height-49, SCREENW, 49);
}
(2)自定義數(shù)字鍵盤適配


適配底部用的一個(gè)宏#define? kTabbarSafeBottomMargin? ? ? ? (IS_iPhoneX ? 34.f : 0.f)用于計(jì)算距離屏幕頂部高度,如果iPhone X,留出距離屏幕底部34安全距離,控件不能顯示34安全距離上


(3)篩選views適配



運(yùn)行程序發(fā)現(xiàn)底部按鈕高度偏高,如圖所示,現(xiàn)在需要調(diào)整底部按鈕距離屏幕頂部高度




(4)適配查看優(yōu)惠券





(5)適配填寫(xiě)訂單




(6)Tabbar沒(méi)有完全遮住

為了遮住TabBar,在iPhone X上tabbar高度增加34,需要調(diào)整遮罩tabbar窗口的高度



八.繼承自UIScrollView的視圖偏移問(wèn)題
我們可以發(fā)現(xiàn)collectionview在iOS11向下偏移64,什原因?qū)е缕?在iOS11之前,如果想要scrollView不偏移64p,則需設(shè)置automaticallyAdjustsScrollViewInsets=NO,但是這個(gè)屬性在iOS11直接被遺棄了??:使用scrollView的屬性contentInsetAdjustmentBehavior來(lái)防止偏移。
UIScrollViewContentInsetAdjustmentAutomatic
UIScrollViewContentInsetAdjustmentScrollableAxes
UIScrollViewContentInsetAdjustmentNever
UIScrollViewContentInsetAdjustmentAlways
這里我們直接選Never就可以了
if (@available(iOS 11.0, *)) {
??_collectionView.contentInsetAdjustmentBehavior = UIApplicationBackgroundFetchIntervalNever;
? ? ?}
但是在iOS11以前系統(tǒng)編譯崩潰,原來(lái)@available(iOS 11.0, *)是iOS 11新增加的,在iOS11以下系統(tǒng)找不到崩潰,為了解決這個(gè)問(wèn)題需要用到條件編譯指令解決這個(gè)問(wèn)題
#ifdef __IPHONE_11_0
if (@available(iOS 11.0, *)) {
_collectionView.contentInsetAdjustmentBehavior = UIApplicationBackgroundFetchIntervalNever;
}
#endif


九.自定義分割線處理
1.iOS 11分割線顏色加深
iOS 11中有的自定義分割線顏色莫名奇妙變深,很難看,如下圖所示,不符合設(shè)計(jì)規(guī)范,嘗試其他方法沒(méi)有解決這個(gè)問(wèn)題,最后通過(guò)改變分割線的透明度來(lái)解決




2.沒(méi)有文字顯示分割線

// 這些界面以下使用代理方法來(lái)設(shè)置,發(fā)現(xiàn)并沒(méi)有生效
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section;
// 這樣的原理是因?yàn)橹爸皇菍?shí)現(xiàn)了高度的代理方法,卻沒(méi)有實(shí)現(xiàn)View的代理方法,iOS10及以前這么寫(xiě)是沒(méi)問(wèn)題的,iOS11開(kāi)啟了行高估算機(jī)制引起的bug,因此有以下幾種解決方法:
// 解決方法一:添加實(shí)現(xiàn)View的代理方法,只有實(shí)現(xiàn)下面兩個(gè)方法,方法 (CGFloat)tableView: heightForFooterInSection: 才會(huì)生效
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
return nil;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
return nil;
}
// 解決方法二:直接使用tableView屬性進(jìn)行設(shè)置,修復(fù)該UI錯(cuò)亂
self.tableView.sectionHeaderHeight = 0;
self.tableView.sectionFooterHeight = 5;
[_optionTableView setContentInset:UIEdgeInsetsMake(-35, 0, 0, 0)];
// 解決方法三:添加以下代碼關(guān)閉估算行高
self.tableView.estimatedRowHeight = 0;
self.tableView.estimatedSectionHeaderHeight = 0;
self.tableView.estimatedSectionFooterHeight = 0;

十.頂部菜單上移,擋住文字適配




十一.適配xib頁(yè)面

注冊(cè)頁(yè)面用xib寫(xiě)的,頁(yè)面tableview距離頂部高度64,寫(xiě)死的,由于導(dǎo)航欄高度在iPhone X和非iPhone X高度不一致,如果都寫(xiě)成64出現(xiàn)下圖問(wèn)題,為了解決這個(gè)問(wèn)題,用到系統(tǒng)自動(dòng)布局NSLayoutConstraint視圖上面,在storyboard 中,通過(guò)拖拽方式,將一個(gè)IBOutlet 拖拽到 .m 文件中如圖所示



十二:信號(hào)欄的字體顏色無(wú)法改變


改變信號(hào)欄方法使用,如果某個(gè)頁(yè)面狀態(tài)欄顏色改變自己定義顏色用這個(gè)方法,針對(duì)iOS11以前使用
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[MCHelpTool changeSignalFormatWithColor:[UIColor whiteColor]];
}
但是在iOS11上狀態(tài)欄的顏色通過(guò)這個(gè)方法無(wú)法改變,狀態(tài)欄機(jī)制發(fā)生變化導(dǎo)致,需要對(duì)該方法進(jìn)行iOS11適配.



/**
*? 改變信號(hào)欄字體顏色
*
*? @param color 顏色參數(shù)
*/
+ (void)changeSignalFormatWithColor:(UIColor *)color{
UIApplication * app = [UIApplication sharedApplication];
id obj = [app valueForKeyPath:@"statusBar"];
if (@available(iOS 11.0, *)) {
if (IS_iPhoneX) {
id obc = [obj valueForKeyPath:@"statusBar"];
unsigned int propertyCount;
objc_property_t * properties = class_copyPropertyList([obc class], &propertyCount);
NSMutableArray * arr = [NSMutableArray arrayWithCapacity:1];
for (int i = 0; i < propertyCount; i++){
objc_property_t property = properties[i];
NSString * propertyStr = [[NSString alloc] initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
if ([propertyStr isEqualToString:@"foregroundColor"]){
[obj setValue:color forKey:propertyStr];
}
[arr sui_addObj:propertyStr];
}
free(properties);
}else{
id ob = [obj valueForKeyPath:@"superclass"];
unsigned int propertyCount;
objc_property_t * properties = class_copyPropertyList([ob class], &propertyCount);
NSMutableArray * arr = [NSMutableArray arrayWithCapacity:1];
for (int i = 0; i < propertyCount; i++){
objc_property_t property = properties[i];
NSString * propertyStr = [[NSString alloc] initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
if ([propertyStr isEqualToString:@"foregroundColor"]){
[obj setValue:color forKey:propertyStr];
}
[arr sui_addObj:propertyStr];
}
free(properties);
}
}else{
unsigned int propertyCount;
objc_property_t * properties = class_copyPropertyList([obj class], &propertyCount);
NSMutableArray * arr = [NSMutableArray arrayWithCapacity:1];
for (int i = 0; i < propertyCount; i++){
objc_property_t property = properties[i];
NSString * propertyStr = [[NSString alloc] initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
if ([propertyStr isEqualToString:@"foregroundColor"]){
[obj setValue:color forKey:propertyStr];
}
[arr sui_addObj:propertyStr];
}
free(properties);
}
}
未完待續(xù)....
參考文章:
iOS11-UISearchBar居中placeholder和icon
UIsearchBar iOS11 像之前的版本那樣沒(méi)有內(nèi)容居中 有內(nèi)容居左
WWDC17: What's New in Location Technologies ?