实验记录
一
// AppDelegate
self.window.rootViewController = [[ViewController alloc] init];
// ViewController
UITableView *tv = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
tv.delegate = self;
tv.dataSource = self;
[self.view addSubview:tv];
没有NavBar,没有设置任何东西,最简单情况。左边为iOS 8,右边为iOS 11。发现iOS 8没有向下偏移,iOS 11向下偏移了20像素。
在iOS 11中决定tableView的内容与边缘距离的是adjustedContentInset
属性。
在iOS 11中,新增了安全区域的概念。由于顶部有状态栏,所以系统会自动计算出tv.adjustedContentInset
值为{20, 0, 0, 0}
。从而使得了tv向下偏移20像素。
二
// AppDelegate
self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:[[ViewController alloc] init]];
// ViewController
UITableView *tv = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
tv.delegate = self;
tv.dataSource = self;
[self.view addSubview:tv];
两者都向下偏移64像素。
在iOS 11以下,控制器有
automaticallyAdjustsScrollViewInsets
属性,默认为YES。
@property(nonatomic,assign) BOOL automaticallyAdjustsScrollViewInsets
API_DEPRECATED("Use UIScrollView's contentInsetAdjustmentBehavior instead", ios(7.0,11.0),tvos(7.0,11.0)); // Defaults to YES
这个属性设置为YES时,系统会自动把tv向下偏移。
而在iOS 11中,可以看到automaticallyAdjustsScrollViewInsets
属性被废弃,但是为什么仍然向下偏移了64像素呢。原因和一一致,现在的安全区域已经变成了NavBar以下,tv.adjustedContentInset
被改为了{64, 0, 0, 0}
,因此也向下偏移64。
三
// AppDelegate
self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:[[ViewController alloc] init]];
// ViewController
UITableView *tv = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
tv.delegate = self;
tv.dataSource = self;
[self.view addSubview:tv];
self.automaticallyAdjustsScrollViewInsets = NO;
三是二的反例。设置了
self.automaticallyAdjustsScrollViewInsets = NO;
,iOS 11以下不偏移了。
四
// AppDelegate
self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:[[ViewController alloc] init]];
// ViewController
self.tv = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
self.tv.delegate = self;
self.tv.dataSource = self;
[self.view addSubview:self.tv];
if (@available(iOS 11.0, *)) {
self.tv.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
} else {
self.automaticallyAdjustsScrollViewInsets = NO;
}
通过设置tv.contentInsetAdjustmentBehavior
为UIScrollViewContentInsetAdjustmentNever
,可以不让系统计算adjustedContentInset
值。从而使得tv不再偏移。
五
// AppDelegate
self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:[[ViewController alloc] init]];
// ViewController
self.navigationController.navigationBar.hidden = YES;
self.view.backgroundColor = [UIColor yellowColor];
self.tv = [[UITableView alloc] initWithFrame:CGRectMake(0, 64, self.view.bounds.size.width, self.view.bounds.size.height - 64) style:UITableViewStylePlain];
self.tv.delegate = self;
self.tv.dataSource = self;
[self.view addSubview:self.tv];
有时候需要自定义导航控制器,这个时候需要把自带的NavBar隐藏。发现在iOS 11以下系统中,tv还是会偏移,并且偏移20像素。而iOS 11就没有问题。
解决办法仍然是设置
automaticallyAdjustsScrollViewInsets
为NO。
iOS 11之前的 automaticallyAdjustsScrollViewInsets
我发现这个属性很有意思。
1 无NavBar
没有设置NavigationController的时候,也就是不存在NavBar的时候,这个属性不会起到作用,tv不会存在偏移问题。
2 有NavBar
2.1 显示NavBar
当设置了NavigationController的时候,并不隐藏NavBar,会默认向下偏移64像素。并且是不管你的NavBar是否遮挡住了tv,都会偏移。下图tv.y = 64
2.2 不显示NavBar
当设置了NavigationController的时候,并隐藏NavBar,会默认向下偏移20像素。并且和2.1一致,无论tv的frame如何,都会偏移。下图tv.y = 64
如果你嫌这个属性麻烦,就设为NO,然后手动管理tv的frame。
总结
经过上面的实验,个人认为,有一个比较好的解决UIScrollView偏移问题的方法。就是在代码中加上下面这一段代码:
if (@available(iOS 11.0, *)) {
self.tv.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
} else {
self.automaticallyAdjustsScrollViewInsets = NO;
}
这样你就可以为所欲为了,科科。