【MISSAJJ原創-iOS】 Xcode9~iOS 11和iPhone X 適配問題集錦

MISSAJJ Projects

前天9月21日,手機更新到iOS 11, 看了一下早期上架 App Store 的應用, 啥問題都沒有, 心里正沾沾自喜也松了一口氣......

可昨夜更新到 Xcode9后編譯代碼,發現還有一些問題的, 因為同時管理了好幾個應用,其他應用也是需要同步作 iOS 11適配, 所以好記不如賴筆頭, 省得適配其他應用的時候忘記.....

問題 1: UINavigationBar 內UIBarButtonItem按鈕錯位拉伸

問題描述:

好在公司的幾個應用的導航欄設計并不復雜, 不需要自定義 titleView,所以不涉及到自定義導航titleView的寬度適配問題.

但是,自定義的 MANavigationController里所重寫的UIBarButtonItem返回按鈕 icon 被拉寬,并且各界面導航欄UIBarButtonItem按鈕, 也同樣擠壓和錯位,設置的 title 也看不到了.

以下2張截圖就是Xcode9編譯代碼發現的iOS 11下UIBarButtonItem按鈕出現的問題:

  • 圖1: 主界面頂部左右3個按鈕被拉伸
    [圖片加載中,請耐心等待....]


    IMG_4897.PNG
  • 圖2: 頂部導航欄中間的 title 消失, 3個按鈕錯位和被拉伸
    [圖片加載中,請耐心等待....]

IMG_4899.PNG

解決方案:

最簡單的解決方案: 將 UIbutton 包裝到 UIview 內, 再通過initWithCustomView方法傳遞給UIBarButtonItem

    //針對 iOS11適配改寫 的關鍵性代碼, 就這么幾行,完全搞定了
    UIView *containVew = [[UIView alloc] initWithFrame:btn.bounds];
    [containVew addSubview:btn];
    return [[UIBarButtonItem alloc]initWithCustomView:containVew];

 以下代碼摘自 MISSAJJ 寫的MAButtonTool工具類,為了節約時間,提高創建按鈕控件的效率,特抽出一個創建各種按鈕的類方法
 
 支持:
 1,圖片按鈕 (默認居中按鈕,左返回按鈕,右分享按鈕)
 2,自定義文字圖片靠左靠右按鈕
 3,按項目需求,設定了按鈕樣式和位置樣式
 4,只要修改一下分享和返回按鈕圖片就可以直接應用到項目中了
 5,由于美工給的圖片素材尺寸會不同,所以按鈕的frame和setImageEdgeInsets可根據項目素材情況在VC層創建后重寫調整
 6,支持block調用按鈕事件
   
 使用方法請看:https://github.com/MISSAJJ/MAButtonTool

^_^ 我只要在這個工具類里針對 iOS 11增加幾行包裝代碼,
就解決了全部項目在 iOS 11下導航欄按鈕錯位問題, 
這就是包裝工具類的好處......


#pragma mark ==[自定義 block 導航欄 按鈕]==
+(UIBarButtonItem *)createButtonWithImage:(NSString * __nullable)imageStr position:(MAButtonToolPostion)position type:(MAButtonToolType)type actionBlock:(ButtonItemBlock)block
{
    UIButton* btn;
    
    if (position == MAButtonToolPostionLeft) { //位置靠左
        
        if (type ==MAButtonToolTypeBack) {  //返回按鈕
            btn = [self createLeftBackButton];
        }else{
            btn = [self createLeftButton:imageStr]; //默認靠左按鈕
        }
        
    }else if (position == MAButtonToolPostionRight) { //位置靠右
        
        if (type ==MAButtonToolTypeShare) {  //分享按鈕
            btn = [self createRightShareButton];
        }else{
            btn = [self createRightButton:imageStr];//默認考右按鈕
        }
        
    }else {  //位置中間
        btn = [self createButton:imageStr];
    }
    
    [btn addTouchAction:^(UIButton *btn) {
        
        if (block)
        {
            block(btn);
        }
        
    }];

    //針對 iOS11適配改寫
    UIView *containVew = [[UIView alloc] initWithFrame:btn.bounds];
    [containVew addSubview:btn];
    return [[UIBarButtonItem alloc]initWithCustomView:containVew];
}


#pragma mark ==[左自定義圖片按鈕]==
+ (UIButton *)createLeftButton:(NSString *)imageStr
{
    UIButton* btn= [self createButton:imageStr]; 
    [btn setImageEdgeInsets:UIEdgeInsetsMake(0, -10, 0, 10)];
    return btn;
}

#pragma mark ==[右自定義圖片按鈕]==
+ (UIButton*)createRightButton:(NSString*)imageStr
{
    UIButton* btn=[self createButton:imageStr];
    [btn setImageEdgeInsets:UIEdgeInsetsMake(0, 10, 0, -10)];
    return btn;
    
}

#pragma mark ==[左返回按鈕]==
+ (UIButton*)createLeftBackButton
{
    UIButton* btn= [self createButton:@"backarrow_white"];
    btn.frame = CGRectMake(0, 0, 50, 50);
    [btn setImageEdgeInsets:UIEdgeInsetsMake(0, -20, 0, 20)];
    return btn;
}

#pragma mark ==[右分享按鈕]==
+ (UIButton*)createRightShareButton
{
    UIButton* btn= [self createButton:@"share_white"];
    btn.frame = CGRectMake(0, 0, 35, 35);
    [btn setImageEdgeInsets:UIEdgeInsetsMake(0, 10, 0, -10)];
    return btn;
}

解決問題后的導航欄顯示截圖

  • 圖1: 導航欄左右3個按鈕顯示正常, 中間的標題也顯示正常了
    [圖片加載中,請耐心等待....]


    IMG_4901.PNG
  • 圖2: 主界面頂部左右3個按鈕顯示正常了
    [圖片加載中,請耐心等待....]


    IMG_4901.PNG

問題 2 : Xcode9下相冊等訪問權限問題

查了資料說iOS11下,蘋果對相冊的權限key做了調整,原來的 NSPhotoLibraryUsageDescription ,在iOS11之后,改成了NSPhotoLibraryAddUsageDescription

針對于此測試了一下應用,果然毫無懸念, 立即去 info.plist 把 key 改成NSPhotoLibraryAddUsageDescription, 很快解決問題了.

圖3: info.plist內設置NSPhotoLibraryAddUsageDescription權限
[圖片加載中,請耐心等待....]


2D3256F9-45E2-412C-B4AF-E66EB262E4B6.png

問題 3 : 等我好好睡個美容覺之后, 再繼續寫吧....... : )

昨夜熬到凌晨3點,適配發布好了[AR 掃描器]APP應用,已經提交審核,
今夜適配另外一個[樂游博物館]APP 應用, 不知不覺又已經凌晨1:00了,

這兩個星期幾乎每天都只睡了幾個小時,

好怕自己迅速變老,
好怕自己腎衰竭猝死,
好怕自己吃東西沒滋味,
好怕自己神經衰落睡不著,

今天可是周末啊! ~周末啊! ~周末啊! ~
.........哎........

問題 4 : MJRefresh下拉刷新適配 iOS 11和 iPhone X問題

熬夜完成了公司的2個應用的 iOS 11適配之后, 今晚開始適配自己的一些項目,打開其中一個項目在不同的模擬器下分別編譯看效果, 底部自定義 tabbar 顯示沒有問題, 但頂部是隱藏了 NavigationBar并采用了MJRefresh下拉刷新,發現有錯位..

圖4: iOS 11下拉刷新出現錯位問題
[圖片加載中,請耐心等待....]


屏幕快照 2017-09-24 01.57.32.png

圖4: iPhone X下拉刷新出現錯位問題
[圖片加載中,請耐心等待....]


屏幕快照 2017-09-24 01.58.03.png

我的解決方案: (灰常簡單)

因為我的布局是 CollectionView, 所以只要設置 iOS 11的新特性方法contentInsetAdjustmentBehavior為UIScrollViewContentInsetAdjustmentNever就可以了
以此類推,如果是 UITableView 布局的,也是設置contentInsetAdjustmentBehavior

判定 iOS 11的方法, 官方建議的方法:

以下是官方的屏幕尺寸, 原本最初的想法就是根據屏幕的高度812pt來判定


圖片.png

官方建議的方法 :

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

我的適配代碼:

if (@available(iOS 11.0, *)) {
      _collectionView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
 } else {
   // Fallback on earlier versions
 }

判定iPhoneX的方法 :


#define isIPhoneX ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? [[UIScreen mainScreen] currentMode].size.height==2436 : NO)

其他的一些相關適配方法:(摘自 MJRefresh討論區的解決方案)

注:首先這個下拉刷新的偏移量并不是MJRefresh造成的,但是確實需要適配,比如通欄ViewController顯示的時候,劉海會遮住下拉刷新的組件,解決辦法是對下拉刷新控件自定義,調整內部組件的布局,通欄的ViewController地方使用自定義的下拉控件。

對于iOS11下的iPhoneX適配下拉刷新有以下幾點:

1,首先請配置相應的啟動圖,尺寸是1125*2436;
2,對于通欄ViewController中的UIScrollView,系統會默認根據contentInsetAdjustmentBehavior屬性改變其bounds的y值為-44,導致UIScrollView中的所有子控件下移,解決辦法是,對于通欄ViewController,請設置其UIScrollView的contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever。

其他適配點:

1,iOS11下的iPhoneX的導航欄為高度44,狀態欄高度也調整為44,所以整個頂部狀態欄的高度和導航欄的高度一起是88,自定義導航欄的同學需要根據系統機型控制導航欄高度;
2,iOS11下的iPhoneX的tabBar的高度調整為83,自定義tabBar的同學建議使用Frame布局;
3,iOS11下的iPhoneX下,屏幕底部默認顯示了長條狀的Home鍵指示器,可以通過UIViewController (UIHomeIndicatorAutoHidden)分類中的prefersHomeIndicatorAutoHidden來隱藏,但是官方并不建議這樣做。

適配 iOS 11和 iPhone X 之后的界面效果

我的建議:
在 iPhone X 下還是最好還是有導航欄的設計比較美觀, 因為隱藏導航欄后, 劉海會把頂部控件切割掉, 畫面就比較尷尬了....哈哈~~

圖5: 適配后的截圖
[圖片加載中,請耐心等待....]


屏幕快照 2017-09-24 02.23.18.png

圖6: 適配后的下拉刷新,同時隱藏導航欄的截圖


圖片.png

圖7: 界面上滑顯示導航欄的效果

屏幕快照 2017-09-24 05.23.34.png

iPhone X 導航欄錯位問題

iOS11下的iPhoneX的導航欄為高度44,狀態欄高度也調整為44,所以整個頂部狀態欄的高度和導航欄的高度一起是88,所以在自定義導航欄里針對 iPhone X 修改的高度

圖片.png

我的解決方法:
我所有的項目都是使用了宏定義參數的方法來設置各種控件的, 所以只要改寫這些相關宏定義參數, 整個項目都同步做好了適配, 所以平時的積累和歸納思維很重要,關鍵時刻可以減輕很多不必要的重復工作量.

/*****宏定義 *****/
//導航欄高度
#define  MANavBarHeight  isIPhoneX ? 88 : 64
//底部Tabbar 高度
#define MATabBarHeight  isIPhoneX ? 83 : 49 
//狀態欄高度
#define  MAStatusBarHeight  isIPhoneX ? 44 : 20
//一些相關同步對應的代碼
// set navigationBar backgroundImage
- (void)MA_setBackgroundImage:(UIImage *)image
{
    [self.backgroundView removeFromSuperview];
    self.backgroundView = nil;
    if (self.backgroundImageView == nil)
    {
        // add a image(nil color) to _UIBarBackground make it clear
        [self setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
        self.backgroundImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.bounds), MANavBarHeight)];
        self.backgroundImageView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
        // _UIBarBackground is first subView for navigationBar
        [self.subviews.firstObject insertSubview:self.backgroundImageView atIndex:0];
    }
    self.backgroundImageView.image = image;
}

// set navigationBar barTintColor
- (void)MA_setBackgroundColor:(UIColor *)color
{
    [self.backgroundImageView removeFromSuperview];
    self.backgroundImageView = nil;
    if (self.backgroundView == nil)
    {
        // add a image(nil color) to _UIBarBackground make it clear
        [self setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
        self.backgroundView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.bounds), MANavBarHeight)];
        self.backgroundView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
        // _UIBarBackground is first subView for navigationBar
        [self.subviews.firstObject insertSubview:self.backgroundView atIndex:0];
    }
    self.backgroundView.backgroundColor = color;
}
其他方法:

網絡里也有相關這種重寫layoutSubviews的方法,我試過之后發現導航欄變透明,并且顏色怪怪的了, 所以最終還是用了上面的方法解決了問題, 下面的這種方法大家也可是嘗試一下

自定義的navigationBar,在iOS11上運行就可能出現布局錯亂的bug,
解決辦法是重寫UINavigationBar的layoutSubviews方法調整布局:

- (void)layoutSubviews {
    [super layoutSubviews];
    
    //注意導航欄及狀態欄高度適配
    self.frame = CGRectMake(0, 0, CGRectGetWidth(self.frame), MANavBarHeight);
    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;
        }
    }
}

適配 iPhone X 之后的截圖

圖片.png

問題 5 : XCode9打包上傳遇到的問題和解決方式

問題:上傳后返回警告,缺失1024px的圖標
圖標缺失
原因和解決: 升級Xcode9后Assets/AppIcon下多了一個1024pt的icon框,需要補上缺失的圖標
1024pt圖標

問題 6 : iPhone X下自定義鍵盤的高度如何增加34px 的高度

iPhone X 的默認系統鍵盤 : 底部會自動加上高度
默認系統鍵盤底部會自動加上高度
問題: 自定義的表情鍵盤的底部在 iPhone X 下沒有增加高度
自定義的鍵盤底部不夠高
將自定義表情emojiToolBarView設置為 UITextView輸入框的inputAccessoryView,emojiToolBarView會置頂于系統鍵盤,并且跟隨系統鍵盤向上向下移動
self.customTextView.inputAccessoryView = self.emojiToolBarView;
將自定義表情toolBar 傳給 UITextView的inputAccessoryView
//點擊自定義表情按鈕事件的邏輯
- (IBAction)emotionBtnClicked:(id)sender {
    UIButton *button = sender;
    
    if (!isEmotionShow) {
        [button setImage:[UIImage imageNamed:@"board_system"] forState:UIControlStateNormal];
        isEmotionShow = YES;
        isKeyboard = NO;
        // self.customEmojiBoardView為自定義表情鍵盤 View
        self.customTextView.inputView = self.customEmojiBoardView;
        [self.customTextView resignFirstResponder];
        
    }else{
        [button setImage:[UIImage imageNamed:@"board_emoji"] forState:UIControlStateNormal];
        isEmotionShow = NO;
        isKeyboard = YES;
        self.customTextView.inputView = nil;
        [self.customTextView resignFirstResponder];
        
    }
}
增加高度后的自定義表情鍵盤
解決辦法: 將你自定義的鍵盤的customEmojiBoardView 的高度加上34就可以了
//自定義表情鍵盤的寬高
 CGFloat viewWidth = [UIScreen mainScreen].bounds.size.width - 16;
//原本自定義的高度是 216, 那就判定 iPhone X 下高度 再加上 34 為: 216+34 ;
 CGFloat viewHeight = isPhoneX ? 250 : 216;

//自定義表情鍵盤customEmojiBoardView 的初始化 
 - (instancetype)init { 
    self = [super initWithFrame:CGRectMake(0, 0,viewWidth, viewHeight)];
    if (self) {
       以下代碼省略...... 
    }
    return self; 
}

最后:

Contact 聯系方式:
希望能有更多的獅子一起共勉探討學習,愉快奔跑!
聯系方式: QQ 996174446 [驗證:iOS 攻城獅]
MISSAJJ網站 : http://www.MISSAJJ.com
Github : https://github.com/MISSAJJ
GitBook : https://www.gitbook.com/@missajj
MISSAJJ琴瑟靜聽( Swift 和 Objective-C )iOS 開發項目電子書
https://github.com/MISSAJJ/MISSAJJ_IOS_DEVELOPMENT_BOOK

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容