NO IMAGE

過了好久,今天終於有時間總結一下適配iPhone X相關的坑,總的來說有兩類坑,一個是導航欄+狀態列的高度發生了變化,一個是一些沒有實現實現-tableView: viewForHeaderInSection:和-tableView: viewForFooterInSection:等代理方法的UITableView會出錯位的問題。

1283539-1f9e771f3c5134b1.png

1. 判斷是否iPhone X:返回YES或NO

1.1 判斷:巨集

(1)依據螢幕解析度

  • 三目運演算法

1
2
//是否iPhoneX YES:iPhoneX螢幕 NO:傳統螢幕
#define kIs_iPhoneX ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(11252436), [[UIScreen mainScreen] currentMode].size) : NO)
  • 多行邏輯判斷

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//是否iPhoneX 1:iPhoneX螢幕 0:傳統螢幕
#define kIs_iPhoneX_test ({\
int tmp = 0;\
if ([UIScreen instancesRespondToSelector:@selector(currentMode)]) {\
    if (CGSizeEqualToSize(CGSizeMake(11252436), [[UIScreen mainScreen] currentMode].size)) {\
        tmp = 1;\
    }else{\
        tmp = 0;\
    }\
}else{\
    tmp = 0;\
}\
tmp;\
})
  • 其中,反斜槓\並不是註釋或者其它的無用符號,其實是多行巨集換行必須要用的標誌。

  • 最後一句tmp;\也是必須的,因為要將經過邏輯判斷得到的tmp作為該巨集的返回值。

(2)依據螢幕尺寸

1
2
3
#define kIs_iPhoneX (kSCREEN_WIDTH == 375.f && kSCREEN_HEIGHT == 812.f)
#define kSCREEN_WIDTH  ([UIScreen mainScreen].bounds.size.width)
#define kSCREEN_HEIGHT ([UIScreen mainScreen].bounds.size.height)

1.2 判斷:方法

  • 方法:依據裝置型號

1
2
3
4
5
6
7
8
9
10
11
+(BOOL)getIs_iPhoneX{
    struct utsname systemInfo;
    uname(&systemInfo);
    NSString *platform = [NSString stringWithCString: systemInfo.machine encoding:NSASCIIStringEncoding];
     
    if([platform isEqualToString:@"iPhone10,3"]||[platform isEqualToString:@"iPhone10,6"]) {
        return YES;
    }else{
        return NO;
    }
}

2. 靈活返回狀態列+導航欄的高度

需求:靈活得到導航欄+狀態列的高度,作為一個子檢視Y軸的起點。

  • 巨集定義

1
#define kStatusBarAndNavigationBarHeight (kIs_iPhoneX ? 88.f : 64.f)
  • 呼叫範例

1
2
//自動適配
_segmentedControl.frame = CGRectMake(0, kStatusBarAndNavigationBarHeight, kSCREEN_WIDTH, 55);

3. 拓展:獲得iOS系統與App版本資訊

  • 獲取iOS系統版本號:返回字串

1
2
3
+ (NSString *)getSystemVersion{
    return [[UIDevice currentDevice] systemVersion];
}
  • 獲取App版本號:返回字串

1
2
3
4
5
6
+ (NSString *)getAppVersion{
    NSDictionary *infoDic = [[NSBundle mainBundle] infoDictionary];
    // 獲取App的版本號
    NSString *appVersion = [infoDic objectForKey:@"CFBundleShortVersionString"];
    return appVersion;
}

4. 適配iPhone X的其他問題

適配iPhone X和Xcode 9的過程中,除了與導航欄相關的問題,還有一個問題經常出現,就是UITableView相關的問題。下面兩個辦法可以解決多數錯位的問題。

  • VC建立tableView屬性的時候這樣設定

1
2
3
self.tableView.estimatedRowHeight = 0;
self.tableView.estimatedSectionHeaderHeight = 0;
self.tableView.estimatedSectionFooterHeight = 0;
  • 還可以這樣設定

1
2
3
4
//cell自適應高度
self.tableView.rowHeight = UITableViewAutomaticDimension;
//預估行高
self.tableView.estimatedRowHeight = 44.0f;
  • 關於根檢視的安全區

iOS新增了個safeArea,原來的老程式碼中,規定子檢視跟根子檢視的關係的程式碼需要新增一個判斷:當iOS 11時,需要改為子檢視跟根子檢視的安全區的關係。這樣就不會在iPhone X的底部虛擬home有任何控制元件干擾了。

1
2
3
4
5
if (@available(iOS 11.0, *)) {
    make.edges.equalTo(self.view.safeAreaInsets)
else {
    make.edges.equalTo(self.view)
}

當然,一般除了tabbar不能放在這個底部虛擬home區,其它的檢視tableView檢視或者網頁檢視時可以放在底部虛擬home區中的。這時候,不需要強調必須把子檢視放在safeArea之內,原來的老程式碼也就不用改。