一.bug展示
Xcode 升级到 9.0beta版本后,公司中的项目运行到iOS11的设备上出现了一个UI Bug,就像下面这种情况.
很显然,tableView有了额外的内边距.代码运行到之前的环境上是没问题的,可用Xcode9一编译,再跑到iOS11上就会出现这么严重的问题...
二.问题产生原因
先贴一段设置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
这个属性,发现这个属性在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
根据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;