iOS11 與 iPhone X適配的那些坑(持更中...)

目錄 問題列表html

1.適配iPhoneX 屏幕原則web

2.適配過程一些常量的設置json

3..iPhone X 上運行有黑色區域問題數組

4.iOS11導航欄適配 xcode

5.出現UIScrollview 漂移問題(基本都是iPhoneX上)安全

6.UITableView 出現的遮擋顯示問題(三行代碼解決,放到基類)bash

7.iOS11 UICollectionview 的scroll indicator等被組視圖遮擋的問題markdown

8.一些關於iPhone X底部的設計示範網絡

9.關於iPhoneX的home條(HomeIndicator)的顯隱app

10.有些致使iPhoneX獲取網絡狀態崩潰的問題

11.關於iOS11權限的變化

12.XCode9添加資源文件不能獲取路徑問題

13.iOS11 沒法彈出鍵盤問題

14.iOS11 數組語法糖🍬替換方法的改變

1. 適配iPhoneX 屏幕原則

圖5 iphoneX 豎屏
 
圖6 iPhoneX 橫屏
 
 

設計原則:讓那行可操做、不可阻擋的控件或視圖顯示在圖五、圖6的藍色區域(安全區域safeArea)。

 
示範圖一

 

 
示範圖二

 

 
示範圖三

頂部危險區距離:44

底部危險區距離:34

2. 適配過程一些常量的設置

#define IS_iPhoneX ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1125, 2436), [[UIScreen mainScreen] currentMode].size) : NO)
//狀態欄高度 
#define kStatusBarHeight    (CGFloat)(IS_iPhoneX?(44):(20))
// iPhoneX的狀態欄高度差值
#define kTopBarDifHeight    (CGFloat)(IS_iPhoneX?(24):(0))
// 頂部安全區域遠離高度
#define kTopBarSafeHeight   (CGFloat)(IS_iPhoneX?(44):(0))
// 狀態欄和導航欄總高度
#define kNavBarHAbove      (CGFloat)(IS_iPhoneX?(88):(64))
// TabBar高度
#define kTabBarHeight       (CGFloat)(IS_iPhoneX?(49+34):(49))
// 底部安全區域遠離高度
#define kBottomSafeHeight   (CGFloat)(IS_iPhoneX?(34):(0))

3. iPhone X 上運行有黑色區域問題

啓動圖問題,使用LaunchScreen來作啓動圖 或者 修改Assets中的LaunchImage,添加iPhoneX的Launch圖1125*2436(px) 豎屏模式。

.

經過LaunchScreen.storyboard方式啓動

若是使用的是Assets中的LaunchImage, 在增長了iPhone X尺寸的圖片配置後.

LaunchScreen.storyboard方式不用多說, 這裏說一下如何在LaunchImage中增長iPhone X尺寸的圖片配置.

方法一:

準備一張尺寸:1125 * 2436的 3x啓動圖片, 移動到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.引導頁iPhone X圖片變形

 

 

 

 

因爲iPhone X高度發生變化,圖片鋪滿整個屏幕時候形成圖片拉伸,如今須要UI切一個1125*2436的3x圖片和之前作iPhone X機型判斷1124*2001圖片,而且對圖片contentMode屬性進行設置

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;//超出區域裁剪

imageView.contentMode = UIViewContentModeScaleAspectFill;//圖片等比例拉伸,會填充整個區域,可是會有一部分過大而超出整個區域

四、導航欄

4.1在解釋導航欄變化以前先解釋一個iOS 11的新特性:設置大標題,經過BOOL類型的prefersLargeTitles屬性來設置。默認設置是不開啓

//顯示大標題「設置」
        self.navigationController.navigationBar.prefersLargeTitles = YES;
        self.navigationItem.title = @"設置";
        //經過navigationItem的largeTitleDisplayMode屬性來設置:
        self.navigationItem.largeTitleDisplayMode =  UINavigationItemLargeTitleDisplayModeAutomatic;
        //其中LargeTitle還有三種樣式能夠選擇:
        UINavigationItemLargeTitleDisplayModeNever//老是顯示小標題
        UINavigationItemLargeTitleDisplayModeAlways//老是顯示大標題
        UINavigationItemLargeTitleDisplayModeAutomatic//自動顯示大標題或小標題。即初始時是大標題,滑動時大標題隱藏、顯示小標題。

4.2. iOS11 系統導航欄上自定義view的顯示問題

以前代碼設置導航欄:

self.navigationItem.titleView = customView;

會出現這樣的問題,以下圖3,

 
圖3 導航欄出錯

界面出亂的緣由是由於iOS11調整了導航欄圖層結構。快速簡便的修改方式,直接上代碼,

self.navigationItem.hidesBackButton = YES;
[self.navigationController.navigationBaraddSubview:YourCustomView];

可是需在控制器的dealloc裏移除你的自定義view,

[YourCustomView removeFromSuperview]; 

下圖4爲修改好的自定義視圖

 
圖4


 
 
 
 
 
 

(1)在iPhone X中導航欄高度變成88,項目中自定義導航欄高度64,須要對導航欄高度進行判斷

_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)搜索框和左右兩邊按鈕高度有問題,由於iPhone X中狀態欄高度由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高度明顯變大,


UISearchBar改變搜索框的高度

系統的searchBar

UISearchBar的中子控件及其佈局

UIView(直接子控件) frame 等於 searchBar的bounds,view的子控件及其佈局

UISearchBarBackground(間接子控件) frame 等於searchBar的bounds

UISearchBarTextField(間接子控件) frame.origin等於(8.0, 6.0),即不等於searchBar的bounds

改變searchBar的frame只會影響其中搜索框的寬度,不會影響其高度,緣由以下:

系統searchBar中的UISearchBarTextField的高度默認固定爲28

左右邊距固定爲8,上下邊距是父控件view的高度減去28除以2

改變UISearchBar的高度

方案

重寫UISearchBar的子類(MCSearchBar),從新佈局UISearchBar子控件的佈局

增長成員屬性contentInset,控制UISearchBarTextField距離父控件的邊距

若用戶沒有設置contentInset,則計算出默認的contentInset

若用戶設置了contentInset,則根據最新的contentInset佈局UISearchBarTextField

新建UISearchBar的子類,增長成員屬性contentInset,用來調整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) {

//說明contentInset已經被賦值

// 根據contentInset改變UISearchBarTextField的佈局

subView.frame = CGRectMake(_contentInset.left, _contentInset.top, width - 2 * _contentInset.left, height - 2 * _contentInset.top);

} else {

// contentSet未被賦值

// 設置UISearchBar中UISearchBarTextField的默認邊距

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);

}

}

}

}

在項目中使用自定義的MCSearchBar,SearchBar的高度能夠改變

(4)iOS11中UISearchBar沒有居中居左顯示,而且icon和placeholder間距太窄

 
 
如今實現居中顯示

@property(nonatomic,assign)CGFloatwidth;

//判斷版本

if(@available(iOS11.0, *)){

UITextField *textField = [self.searchBar valueForKey:@"searchField"];

[textField sizeToFit];

//記錄一下這個時候的寬度

_width= textField.frame.size.width;

[_searchBar setPositionAdjustment:UIOffsetMake((_searchBar.width-_width)/2.0,0)forSearchBarIcon:UISearchBarIconSearch];

}

而後在代理方法 searchBarTextDidBeginEditing:(UISearchBar*)searchBar 調整位置

- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar{

if (@available(iOS 11.0, *)) {

if(!_searchBar.text.length) {

[_searchBar setPositionAdjustment:UIOffsetMake(0,0)forSearchBarIcon:UISearchBarIconSearch];

}

}

}

結束的方法  searchBarTextDidEndEditing:(UISearchBar*)searchBar 判斷是否有內容

- (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];

}

}

}

若是有佔位文字後臺返的,UITextField在搜索框默認文字大小17,能夠根據文字個數和大小算出佔位文字寬度,而後算出搜索圖標的偏移量.


 

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

 

 

 
 

self.searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, testView.width - (SCREENW > 320 ? 90: 100)*SCREEN_Proportion, testView.height)];

因爲搜索框距離左邊距離致使的,如今須要定義一個宏作判斷

#define marginLeft (IS_iPhoneX ? 10 : 0)

self.searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(marginLeft, 0, testView.width - (SCREENW > 320 ? 90: 100)*SCREEN_Proportion, testView.height)];

 

 

5. 出現UIScrollview 漂移問題(基本都是iPhoneX上)

如果UIScrollview的frame和contentSize高度或者寬度一致卻還致使了漂移問題,可用如下一行代碼搞定。

if(@available(iOS11,*)) {_scrollView.contentInsetAdjustmentBehavior=UIScrollViewContentInsetAdjustmentNever;}

同時,若是在push進入webview頁面時,底部會有黑邊一閃而過,也可用此方法解決。

若嫌麻煩,每一個scrollview及其子類都要去設置的話,也可使用如下方法

// AppDelegate 裏進行全局設置 if(@available(iOS 11.0, *)){[[UIScrollView appearance] setContentInsetAdjustmentBehavior:UIScrollViewContentInsetAdjustmentNever];

 

 

 

 

 
 

 

四:UITableview UICollectionView MJRefresh下拉刷新錯亂

 
 
 
 
 
 
 
 
 
 

iOS11表格用MJRefresh框架下拉刷新的時候界面會閃,顯示紊亂,

緣由是iOS11棄用了automaticallyAdjustsScrollViewInsets屬性,新增contentInsetAdjustmentBehavior來替代它

tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;

解決方法:MJRefresh做者已經針對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中底部工具欄須要爲home indicator留出34pt邊距,iPhone X之前機型TarBar高度49,iPhone X中Tarbar高度加上34變成83.因爲項目中Tabbar是用自定義的,須要對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)];

 

 

圖標和文字和其餘機型相比偏下,如今須要對圖標和文字高度進行調整,作iPhone X和非iPhone X機型適配

 

 

 

 

 

七.底部view出現問題

 

(1)購物車View適配,涉及頁面商品詳情頁,搜索頁面,購物車頁面

 

 

 

 

 

 

 

(2)自定義數字鍵盤適配

 

 

 

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

 

適配前代碼

 

適配後代碼

 

(3)篩選views適配

 

適配前

 

適配後

 

 九.自定義分割線處理

1.iOS 11分割線顏色加深

iOS 11中有的自定義分割線顏色莫名奇妙變深,很難看,以下圖所示,不符合設計規範,嘗試其餘方法沒有解決這個問題,最後經過改變分割線的透明度來解決

 

適配前

適配後

2.沒有文字顯示分割線

// 這些界面如下使用代理方法來設置,發現並無生效

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section;

// 這樣的原理是由於以前只是實現了高度的代理方法,卻沒有實現View的代理方法,iOS10及之前這麼寫是沒問題的,iOS11開啓了行高估算機制引發的bug,所以有如下幾種解決方法:

// 解決方法一:添加實現View的代理方法,只有實現下面兩個方法,方法 (CGFloat)tableView: heightForFooterInSection: 纔會生效

- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {

return nil;

}

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {

return nil;

}

// 解決方法二:直接使用tableView屬性進行設置,修復該UI錯亂

self.tableView.sectionHeaderHeight = 0;

self.tableView.sectionFooterHeight = 5;

[_optionTableView setContentInset:UIEdgeInsetsMake(-35, 0, 0, 0)];

// 解決方法三:添加如下代碼關閉估算行高

3. UITableView 出現的遮擋顯示問題(三行代碼解決,放到基類)

self.tableView.estimatedRowHeight = 0;
self.tableView.estimatedSectionHeaderHeight = 0;
self.tableView.estimatedSectionFooterHeight = 0;

8.有些致使iPhoneX獲取網絡狀態崩潰的問題

直接上代碼,無需經過KVC獲得圖層名獲取網絡狀態,一勞永逸!(因還不熟悉markdown語法,如下代碼需自行縮進

#import <CoreTelephony/CTTelephonyNetworkInfo.h>
+ (NSString *)getNetWorkInfo {
    NSString *strNetworkInfo = @"No Network";
    struct sockaddr_storage zeroAddress;
    bzero(&zeroAddress,sizeof(zeroAddress));
    zeroAddress.ss_len = sizeof(zeroAddress);
    zeroAddress.ss_family = AF_INET;
// Recover reachability flags
    SCNetworkReachabilityRef defaultRouteReachability = SCNetworkReachabilityCreateWithAddress(NULL,(struct sockaddr *)&zeroAddress);
    SCNetworkReachabilityFlags flags;
//得到鏈接的標誌   
    BOOL didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability,&flags);
    CFRelease(defaultRouteReachability);
//若是不能獲取鏈接標誌,則不能鏈接網絡,直接返回
    if(!didRetrieveFlags){ return strNetworkInfo;}     BOOL isReachable = ((flags & kSCNetworkFlagsReachable)!=0); BOOL needsConnection = ((flags & kSCNetworkFlagsConnectionRequired)!=0); if(!isReachable || needsConnection) {return strNetworkInfo;} // 網絡類型判斷
    if((flags & kSCNetworkReachabilityFlagsConnectionRequired)== 0){strNetworkInfo = @"WIFI";}   
    if(((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) ||(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0) { if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0){strNetworkInfo = @"WIFI";}}
    if ((flags & kSCNetworkReachabilityFlagsIsWWAN) ==kSCNetworkReachabilityFlagsIsWWAN) {if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {CTTelephonyNetworkInfo * info = [[CTTelephonyNetworkInfo alloc] init];NSString *currentRadioAccessTechnology = info.currentRadioAccessTechnology;if (currentRadioAccessTechnology) {if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyLTE]) {strNetworkInfo =  @"4G";} else if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyEdge] || [currentRadioAccessTechnologyisEqualToString:CTRadioAccessTechnologyGPRS]) {strNetworkInfo =  @"2G";} else {strNetworkInfo =  @"3G";}}} else {if((flags & kSCNetworkReachabilityFlagsReachable) == kSCNetworkReachabilityFlagsReachable) {if ((flags & kSCNetworkReachabilityFlagsTransientConnection) == kSCNetworkReachabilityFlagsTransientConnection) {if((flags & kSCNetworkReachabilityFlagsConnectionRequired) == kSCNetworkReachabilityFlagsConnectionRequired) {strNetworkInfo = @"2G";} else {strNetworkInfo = @"3G";}}}}}
    // if ([strNetworkInfo isEqualToString: @"No Network"]) {strNetworkInfo = @"WWAN";}
    return strNetworkInfo;
}

 10. 關於iPhoneX的home條(HomeIndicator)的顯隱

先看下圖7,

 
圖7 橫屏看撩妹視頻時

這樣的體驗實際上是很差的(還怎麼用英文撩妹?),因此爲了以防這樣的問題出現,蘋果其實提供了隱藏HomeIndicator的方法,以下,

- (BOOL)prefersHomeIndicatorAutoHidden {
  return YES;
}

在VC 裏邊重寫 prefersHomeIndicatorAutoHidden 返回 YES(默認是NO),Home指示條就能自動隱藏了,此方法是在屏幕若無交互事件響應時,延遲2秒左右會回調此方法。

11. 關於iOS11權限的變化

1.定位問題:沒法定位,第一次使用時沒有彈出定位請求對話框。

緣由:因爲iOS11的定位權限的key作了更改,在之前iOS11以前的始終容許定位NSLocationAlwaysUsageDescription基礎上添加NSLocationWhenInUseUsageDescription和NSLocationAlwaysAndWhenInUsageDescription。具體參考博客:http://blog.csdn.net/dangyalingengjia/article/details/77965029

2.相冊權限問題:iOS11上讀寫相冊的照片時發生崩潰。

緣由:因爲iOS11相冊相關權限的key發生了變化。用戶在沒有權限的狀況下,訪問相冊致使崩潰。

iOS11以前對應的key是NSPhotoLibraryUsageDescription,而iOS11的Key變爲NSPhotoLibraryAddUsageDescription。同定位的Key同樣,因爲key沒有兼容性,因此須要保留原key以兼容iOS11以前的版本。

12. iOS11 UICollectionview 的scroll indicator等被組視圖遮擋的問題

問題以下圖8紅框區域,

 
圖8 UICollectionview bug圖

致使這個的緣由是由於組視圖的z座標出現了問題, 有如下兩種解決辦法

第一種: 在該類中重寫layoutSubviews方法<適用於小規模>

- (void)layoutSubviews {
    [super layoutSubviews];
    self.layer.zPosition = 0;
}

第二種: 自定義一個layer, 重寫其zPosition的get方法。而後對組視圖類添加分類方法,重寫layerClass方法便可。

自定義layer:

@implementation YYZPositionZeroLayer

- (CGFloat)zPosition {
    return 0;
}
@end

添加分類重寫組視圖layerClass方法:

@implementationUICollectionReusableView (ZPositionZero)
+ (Class)layerClass {
  return[YYZPositionZeroLayer class];
}
@end

12. XCode9添加資源文件不能獲取路徑問題

XCode9調用[[NSBundle mainBundle] pathForResource:resourceNameofType:nil];方法來獲取文件路徑,返回爲nil. 添加正確方式以下圖1,

 
圖1  添加資源選項

可是XCode9 卻埋了一道坑,以下圖2, 點擊資源文件,找到文件選項

 
圖2  資源文件選項

紅框區域未默認勾選, 只要把這個複選框勾選便可解決.  具體緣由是:xcode9 添加文件使用addfile 拖拽的文件不會自動添加到Compile Sources 和 Copy Bundle Resources 下.

13. iOS11 沒法彈出鍵盤問題

問題描述: 在某些時候你會發現調用becomeFirstResponder方法時,並未響應鍵盤,系統鍵盤沒法彈出.

問題發現: 若是在調用以前使用了UIAlertView彈出對話框,就會致使系統鍵盤沒法彈出,猜想是由於UIAlertView在消失遍歷window窗口時存在windowLevel 大於 levelNormal 的window把他做爲keywindow

問題解決: 若是你的項目裏面還在使用UIAlertView(2_0,9_0), 建議用UIAlertController替換掉.

14.iOS11 數組語法糖🍬替換方法的改變

在iOS11 以前,

array[i] 語法糖的替換方法是[array objectAtIndex:i]

在iOS11 以後,

array[i] 語法糖的替換方法是[array objectAtIndexedSubscript:i]

用到動態交換方法的童鞋須要注意

free(properties);

}

相關文章
相關標籤/搜索