一.bug展示
Xcode 升級到 9.0beta版本后,公司中的項目運行到iOS11的設備上出現(xiàn)了一個UI Bug,就像下面這種情況.
很顯然,tableView有了額外的內邊距.代碼運行到之前的環(huán)境上是沒問題的,可用Xcode9一編譯,再跑到iOS11上就會出現(xiàn)這么嚴重的問題...
二.問題產生原因
先貼一段設置tableView的代碼
private func setupTableView() {
tableView = UITableView()
tableView.frame = view.bounds
tableView.dataSource = self
tableView.delegate = self
tableView.backgroundColor = UIColor.red
// 公司的項目中導航欄是不透明的,所以需要加上這兩行代碼,我們自己來計算scrollView的內邊距
extendedLayoutIncludesOpaqueBars = true;
automaticallyAdjustsScrollViewInsets = false;
// 設置tableView的內邊距(能夠顯示出導航欄和tabBar下覆蓋的內容)
tableView.contentInset = UIEdgeInsetsMake(64, 0, 49, 0)
// 設置內容指示器(滾動條)的內邊距
tableView.scrollIndicatorInsets = tableView.contentInset
}
關于extendedLayoutIncludesOpaqueBars
和automaticallyAdjustsScrollViewInsets
- 這兩個屬性屬于UIViewController
- 默認情況下
extendedLayoutIncludesOpaqueBars = false
擴展布局不包含導航欄 - 默認情況下
automaticallyAdjustsScrollViewInsets = true
自動計算滾動視圖的內容邊距 - 但是,當 導航欄 是 不透明時,而tabBar為透明的時候,為了正確顯示tableView的全部內容,需要重新設置這兩個屬性的值,然后設置contentInset(參考代碼).
上面的代碼邏輯沒有問題,但是放到iOS11 上為啥錯了呢?
找了半天,點開了automaticallyAdjustsScrollViewInsets
這個屬性,發(fā)現(xiàn)這個屬性在iOS11過期了,如圖:
在OC的聲明中,這個屬性是這樣的:
@property(nonatomic,assign) BOOL automaticallyAdjustsScrollViewInsets API_DEPRECATED_WITH_REPLACEMENT("Use UIScrollView's contentInsetAdjustmentBehavior instead", ios(7.0,11.0),tvos(7.0,11.0)); // Defaults to YES
這說明在iOS11 中, UIViewController的
automaticallyAdjustsScrollViewInsets
屬性已經不再使用,我們需要使用UIScrollView的 contentInsetAdjustmentBehavior
屬性來替代它.
關于contentInsetAdjustmentBehavior
@available(iOS 11.0, *)
public enum UIScrollViewContentInsetAdjustmentBehavior : Int {
case automatic // Similar to .scrollableAxes, but will also adjust the top & bottom contentInset when the scroll view is owned by a view controller with automaticallyAdjustsScrollViewContentInset = YES inside a navigation controller, regardless of whether the scroll view is scrollable
case scrollableAxes // Edges for scrollable axes are adjusted (i.e., contentSize.width/height > frame.size.width/height or alwaysBounceHorizontal/Vertical = YES)
case never // contentInset is not adjusted
case always // contentInset is always adjusted by the scroll view's safeAreaInsets
}
UIScrollViewContentInsetAdjustmentBehavior 是一個枚舉類型,值有以下幾種:
-
automatic
和scrollableAxes一樣,scrollView會自動計算和適應頂部和底部的內邊距并且在scrollView 不可滾動時,也會設置內邊距. -
scrollableAxes
自動計算內邊距. -
never
不計算內邊距 -
always
根據(jù)safeAreaInsets 計算內邊距
很顯然,我們這里要設置為never
三.開始適配
swift 中
private func setupTableView() {
tableView = UITableView()
tableView.frame = view.bounds
tableView.dataSource = self
tableView.delegate = self
tableView.backgroundColor = UIColor.red
extendedLayoutIncludesOpaqueBars = true;
if #available(iOS 11.0, *) {
tableView.contentInsetAdjustmentBehavior = .never
} else {
automaticallyAdjustsScrollViewInsets = false;
};
tableView.contentInset = UIEdgeInsetsMake(64, 0, 49, 0)
tableView.scrollIndicatorInsets = tableView.contentInset
}
OC 中
self.extendedLayoutIncludesOpaqueBars = YES;
if (@available(iOS 11.0, *)) {
self.tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
} else {
self.automaticallyAdjustsScrollViewInsets = NO;
}
_tableView.contentInset = UIEdgeInsetsMake(64, 0, 49, 0);
_tableView.scrollIndicatorInsets = _tableView.contentInset;