1. 程式人生 > >適配iOS 11和iPhone X——導航欄、UITableView

適配iOS 11和iPhone X——導航欄、UITableView

每年的WWDC大會都激動和緊張好一段時間。激動的是期待蘋果的新產品帶來的那些黑科技,尤其今年的iPhone10週年紀念款iPhone X。緊張的當然是iOS、Swift和Xcode的升級,又要加班了(ㄒoㄒ)。在這裡跟大家分享一下適配iOS 11和iPhone X的過程中,遇到了一些坑。

一、導航欄

在解釋導航欄變化之前先解釋一個iOS 11的新特性:設定大標題,通過BOOL型別的prefersLargeTitles屬性來設定。預設設定是不開啟。

//顯示大標題“設定”

self.navigationController.navigationBar.prefersLargeTitles
= YES; self.navigationItem.title = @"設定";

1
其中LargeTitle還有三種樣式可以選擇:

UINavigationItemLargeTitleDisplayModeNever//總是顯示小標題

UINavigationItemLargeTitleDisplayModeAlways//總是顯示大標題

UINavigationItemLargeTitleDisplayModeAutomatic//自動顯示大標題或小標題。即初始時是大標題,滑動時大標題隱藏、顯示小標題。

通過navigationItem的largeTitleDisplayMode屬性來設定:

self.navigationItem.largeTitleDisplayMode =  UINavigationItemLargeTitleDisplayModeAutomatic;

當然,只有當prefersLargeTitles為YES時largeTitleDisplayMode屬性才生效。

1、導航欄高度變化

iOS 11之前導航欄預設高度為64pt(statusBar + NavigationBar),iOS11之後如果設定了prefersLargeTitles = YES則為96pt,預設情況下還是64pt。由於iPhoneX上出現了“劉海”,statusBar由以前的20pt變成了44pt,所以iPhoneX上高度變為88pt。

2、導航欄圖層變化

iOS 11之前導航欄的title是新增在UINavigationItemView上面的,而navigationBarButton則是直接條件在navigationBar上面。如果設定了titleView,那麼titleView也是直接新增在navigationBar上面的。
2

iOS 11之後,檢視層級發生了變化,增添了新的管理類。navigationBar會新增在_UIButtonBarStackView上面,而_UIButtonBarStackView則新增在_UINavigationBarContentView上面。
如果沒有給titleView賦值,那麼titleView會直接新增在_UINavigationBarContentView上面;如果賦值了titlev,那麼titleview會新增在_UITAMICAdaptorView上面,_UITAMICAdaptorView會新增在_UINavigationBarContentView上面。
3

這裡寫圖片描述

所以如果你的專案是自定義的navigationBar,那麼在iOS11上執行就可能出現佈局錯亂的bug,解決辦法是重寫UINavigationBar的layoutSubviews方法,調整佈局。

- (void)layoutSubviews {
    [super layoutSubviews];

    //注意導航欄及狀態列高度適配
    self.frame = CGRectMake(0, 0, 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;
        }
    }
}

二、UIScrollView、UITableView、UICollectionView

在iOS 11之前,如果想要scrollView不偏移64pt,則設定automaticallyAdjustsScrollViewInsets = NO,現在iOS 11裝置上執行出現最多問題應該就是tableview莫名奇妙的偏移20pt或者64pt了。原因就是iOS 11棄用了automaticallyAdjustsScrollViewInsets屬性,取而代之的是UIScrollView新增的contentInsetAdjustmentBehavior屬性。最終還是因為iOS 11新添了safeArea。

另外,tableView的sectionHeader、sectionFooter高度與設定不符的問題,因為在iOS 11中如果不實現

-tableView: viewForHeaderInSection:
-tableView: viewForFooterInSection:

則不會被呼叫

-tableView: heightForHeaderInSection:
- tableView: heightForFooterInSection:

導致sectionHeader、sectionFooter的高度都變成了預設高度。
iOS 11之前,設定sectionHeader、sectionFooter高度為0時,需要設定height=0.1,才會起作用,如果直接設定為0,則會使用預設高度。在iOS 11中預設使用Self-Sizing,tableView的estimatedRowHeight、estimatedSectionHeaderHeight、 estimatedSectionFooterHeight三個高度估算屬性由預設的0變成了UITableViewAutomaticDimension,解決辦法簡單粗暴,就是實現對應方法或把這三個屬性設為0。

如果你使用了Masonry,那麼你需要適配safeArea

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