天天看點

如何适配iOS11和iPhoneX導航欄導航欄高度的變化iPhoneXLaunchImage

随着iOS11正式版的推送和iPhoneX的即将到來,是時候為我們的App做新一輪的适配,下面我來總結下我們項目中遇到的一些問題。

導航欄

導航欄高度的變化

iOS11之前導航欄預設高度為64pt(這裡高度指statusBar + NavigationBar),iOS11之後如果設定了

prefersLargeTitles = YES

則為96pt,預設情況下還是64pt,但在iPhoneX上由于劉海的出現statusBar由以前的20pt變成了44pt,是以iPhoneX上高度變為88pt,如果項目裡隐藏了導航欄加了自定義按鈕之類的,這裡需要注意适配一下。

導航欄圖層及對titleView布局的影響

iOS11之前導航欄的title是添加在

UINavigationItemView

上面,而navigationBarButton則直接添加在

UINavigationBar

上面,如果設定了titleView,則titleView也是直接添加在

UINavigationBar

上面。iOS11之後,大概因為

largeTitle

的原因,視圖層級發生了變化,如果沒有給titleView指派,則titleView會直接添加在

_UINavigationBarContentView

上面,如果指派了titleView,則會把titleView添加在

_UITAMICAdaptorView

上,而navigationBarButton被加在了

_UIButtonBarStackView

上,然後他們都被加在了

_UINavigationBarContentView

上,如圖:

如何适配iOS11和iPhoneX導航欄導航欄高度的變化iPhoneXLaunchImage

圖1

是以如果你的項目是自定義的navigationBar,那麼在iOS11上運作就可能出現布局錯亂的bug,解決辦法是重寫

UINavigationBar

layoutSubviews

方法,調整布局,上代碼:

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

           

再補充一點,看了簡書App适配iOS11發現titleView支援

autolayout

,這要求titleView必須是能夠自撐開的或實作了

- intrinsicContentSize

方法

- (CGSize)intrinsicContentSize {
    return UILayoutFittingExpandedSize;
}

           

UIScrollView、UITableView、UICollectionView

大家在iOS11裝置上運作出現最多問題應該就是

tableview

莫名奇妙的偏移20pt或者64pt了。。原因是iOS11棄用了

automaticallyAdjustsScrollViewInsets

屬性,取而代之的是

UIScrollView

新增了

contentInsetAdjustmentBehavior

屬性,這一切的罪魁禍首都是新引入的

safeArea

,關于

safeArea

适配這篇文章iOS 11 安全區域适配總結講的很詳細,感興趣的可以看下,我直接貼适配代碼,因為低版本直接用

contentInsetAdjustmentBehavior

會報警告,所有定義了如下的宏:

#define  adjustsScrollViewInsets(scrollView)\
do {\
_Pragma("clang diagnostic push")\
_Pragma("clang diagnostic ignored \"-Warc-performSelector-leaks\"")\
if ([scrollView respondsToSelector:NSSelectorFromString(@"setContentInsetAdjustmentBehavior:")]) {\
    NSMethodSignature *signature = [UIScrollView instanceMethodSignatureForSelector:@selector(setContentInsetAdjustmentBehavior:)];\
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];\
    NSInteger argument = ;\
    invocation.target = scrollView;\
    invocation.selector = @selector(setContentInsetAdjustmentBehavior:);\
    [invocation setArgument:&argument atIndex:];\
    [invocation retainArguments];\
    [invocation invoke];\
}\
_Pragma("clang diagnostic pop")\
} while ()

           

還有的發現某些界面

tableView

sectionHeader

sectionFooter

高度與設定不符的問題,在iOS11中如果不實作

-tableView: viewForHeaderInSection:

-tableView: viewForFooterInSection:

,則

-tableView: heightForHeaderInSection:

- tableView: heightForFooterInSection:

不會被調用,導緻它們都變成了預設高度,這是因為

tableView

在iOS11預設使用

Self-Sizing

tableView

estimatedRowHeight

estimatedSectionHeaderHeight

estimatedSectionFooterHeight

三個高度估算屬性由預設的0變成了

UITableViewAutomaticDimension

,解決辦法簡單粗暴,就是實作對應方法或把這三個屬性設為0。

如果你使用了

Masonry

,那麼你需要适配

safeArea

if (@available(iOS , *)) {
    make.edges.equalTo()(self.view.safeAreaInsets)
} else {
    make.edges.equalTo()(self.view)
}

           

iPhoneX

LaunchImage

關于iPhoneX(我就不吐槽劉海了...),如果你的APP在iPhoneX上運作發現沒有充滿螢幕,上下有黑色區域,那麼你應該也像我一樣

LaunchImage

沒有用

storyboard

而是用的

Assets

,解決辦法如圖,啟動圖的尺寸為

1125x2436

,or you can iOS開發時如何使用 Launch Screen Storyboard。

如何适配iOS11和iPhoneX導航欄導航欄高度的變化iPhoneXLaunchImage

圖2

TabBarController

因為我們的項目用了第三方的

TabBarController

,在iPhoneX運作,tabBar看起來怪怪的...估計作者要等到猴年馬月才适配iPhoneX,項目又着急上線,就自己修改了第三方,主要是

tabBar

高度及

tabBarItem

偏移适配,iPhoneX由于底部安全區的原因

UITabBar

高度由49pt變成了83pt,可以通過判斷機型來修改相關界面代碼,方式有兩種,通過分辨率判斷:

#define kDevice_Is_iPhoneX ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1125, 2436), [[UIScreen mainScreen] currentMode].size) : NO)

           

通過裝置名稱判斷:

@"iPhone10,1" : @"iPhone 8",

@"iPhone10,4" : @"iPhone 8",

@"iPhone10,2" : @"iPhone 8 Plus",

@"iPhone10,5" : @"iPhone 8 Plus",

@"iPhone10,3" : @"iPhone X",

@"iPhone10,6" : @"iPhone X",

這裡推薦使用UIDeviceIdentifier。

目前遇到的就這些問題,後續再遇到會繼續補充~

繼續閱讀