原因
-
iOS11中
UIViewController
的automaticallyAdjustsScrollViewInsets
属性已经不再使用,我们需要使用UIScrollView
的contentInsetAdjustmentBehavior
属性来替代它。
当UIScrollView
的frame
超出安全区域范围时,系统会自动调整UIScrollView
的safeAreaInsets
值,于是会影响UIScrollView
的adjustContentInset
值,从而导致UIScrollView
的内容发生偏移。iOS11 控制UIScrollView
内容偏移量的属性是adjustContentInset
,而adjustContentInset
值是系统根据safeAreaInsets
、contentInset
计算得来的,计算方式由contentInsetAdjustmentBehavior
决定。 -
补充:有导航栏时
safeAreaInsets
值自动调整为(88,0,34,0)。没有导航栏时safeAreaInsets
值为(44,0,34,0)。
安全区域
-
安全区域是iOS 11新提出的。
-
安全区域帮助我们将
view
放置在整个屏幕的可视的部分。即使把navigationBar
设置为透明的,系统也认为安全区域是从navigationBar
的bottom
开始,保证不被系统的状态栏、或导航栏覆盖。controller
可以使用additionalSafeAreaInsets
去扩展安全区域使它包括自定义的content在界面上。每个view
都可以改变安全区域嵌入的大小,controller
也可以。 -
safeAreaInsets
属性反映了一个view
距离该view
的安全区域的边距。对于一个UIViewController
的根视图而言,safeAreaInsets
值包括了被statusbar
和其他可视的bars
覆盖的区域和其他通过additionalSafeAreaInsets
自定义的insets
值。view
层次中的其它view
,safeAreaInsets
值反映了该view
被覆盖的部分。如果一个view
全部在它父视图的安全区域内,则safeAreaInsets
值为(0,0,0,0)。
adjustContentInset 属性的计算方式
首先看UIScrollView
在iOS11新增的两个属性:adjustContentInset
和 contentInsetAdjustmentBehavior
。
-
UIScrollViewContentInsetAdjustmentAutomatic
:如果scrollView
在一个automaticallyAdjustsScrollViewContentInset = YES
的UIViewController
上,并且这个UIViewController
包含在一个UINavigationController
中,这种情况下会设置在top & bottom
上adjustedContentInset = safeAreaInset + contentInset
不管是否滚动。其他情况下与UIScrollViewContentInsetAdjustmentScrollableAxes
相同。 -
UIScrollViewContentInsetAdjustmentScrollableAxes
: 在可滚动方向上adjustedContentInset = safeAreaInset + contentInset
,在不可滚动方向上adjustedContentInset = contentInset
;依赖于scrollEnabled
和alwaysBounceHorizontal / Vertical = YES
,scrollEnabled
默认为Yes
,所以大多数情况下,计算方式还是adjustedContentInset = safeAreaInset + contentInset
-
UIScrollViewContentInsetAdjustmentNever
:adjustedContentInset = contentInset
。当contentInsetAdjustmentBehavior
设置为UIScrollViewContentInsetAdjustmentNever
的时候,adjustContentInset
值不受safeAreaInset
值的影响。 -
UIScrollViewContentInsetAdjustmentAlways
:adjustedContentInset = safeAreaInset + contentInset
解决方法
-
重新设置
tableView
的contentInset
值,来抵消掉safeAreaInset
值,因为adjustedContentInset = contentInset + safeAreaInset
; -
设置
tableView
的contentInsetAdjustmentBehavior
属性为UIScrollViewContentInsetAdjustmentNever
,这样adjustedContentInset = contentInset
;
// 新API:`@available(iOS 11.0, *)` 可用来判断系统版本
if ( @available(iOS 11.0, *) ) {
self.tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}
- 设置iOS11
UIViewController
新增属性addtionalSafeAreaInset
;
iOS 11之前,大家是通过将UIViewController
的automaticallyAdjustsScrollViewInsets
属性设置为NO,来禁止系统调整tableView
的contentInset
。如果还是想从controller
级别解决问题,可以通过设置controller
的additionalSafeAreaInsets
属性,因为当tableView
的frame
没有超出安全区域范围时,系统就不会调整tableView
的safeAreaInset
值,从而也就不会发生内容偏移情况。
组头组尾高度
-
当
tableView
的类型为UITableViewStyleGrouped
时,系统默认tableView
组头和组尾是有间距的,如果不需要这个间距的话,iOS11之前可以通过实现代理方法heightForHeaderInSection / heightForFooterInSection
(返回一个较小值:0.01)来解决的。 -
iOS11之后不仅要实现代理方法
heightForHeaderInSection / heightForFooterInSection
,还要实现代理方法viewForHeaderInSection / viewForFooterInSection
才能去掉间距。或者添加以下代码关闭高度估算,问题也能解决。
self.tableView.estimatedRowHeight = 0;
self.tableView.estimatedSectionHeaderHeight = 0;
self.tableView.estimatedSectionFooterHeight = 0;
网友评论