之前寫過一篇文章描述了下影響頁面布局的幾個屬性,如今iOS 11出來后變化挺大的,在這里重新梳理下。
可以看到在iOS 11
中,UIViewController的automaticallyAdjustsScrollViewInsets
屬性被棄用了,系統推薦我們使用UIScrollView的contentInsetAdjustmentBehavior
屬性替代之。關于這個屬性,系統提供了四種行為模式:
UIScrollViewContentInsetAdjustmentAutomatic
UIScrollViewContentInsetAdjustmentScrollableAxes
UIScrollViewContentInsetAdjustmentNever
UIScrollViewContentInsetAdjustmentAlways
第3、4種看起來比較清晰,要么不調整,要么"一直"調整。但估計不少朋友看到第1、2種會一臉懵逼,包括第4種里“一直”這個詞。在這解釋之前我們先分析下為什么automaticallyAdjustsScrollViewInsets
會被棄用。
在我看來原因可能之前使用automaticallyAdjustsScrollViewInsets
的方案太單調粗暴了。回顧以前所說的,當處于 ①(文末)情況時的scrollView,系統會自動修改其contentInset
屬性,舉個例子:如果存在狀態欄
和導航欄
,則contentInset
的top
值則會被修改為64,內容自動下移64。當底部存在系統UITabBar
時,則bottom
值修改為49,即下方額外增加49的滾動距離。
我們知道iOS 11
后引入了安全區的概念safeAreaInsets
。
以不帶UITabBar
的iPhone X
為例:NavigationController的rootViewController.view(以下用self
代稱該rootViewController),其safeAreaInsets
為{88, 0, 34, 0}
,在contentInsetAdjustmentBehavior
屬性出現之前,系統是根據①情況進行的調整。而現在,系統將會根據ScrollView視圖大小(包括其類族UITableView等)是否超過了安全區來進行調整,需要注意的有兩點:
- 這個"調整"不再是直接修改
scrollView.contentSize
,而是scrollView.adjustedContentInset
- 調整的值將根據具體超出多少值來確定,但最大值不能超過安全區的相應EdgeInsets方向的值。以self.view的
safeAreaInsets
為{88, 0, 34, 0}
為例。此時添加一個tableView,其高度為self.view.short_height + 25
,那么tableView.adjustedContentInset
的bottom
則為25。但如果超出高度為134,bottom
最高也只會是34,這樣就會由于表格高度超過屏幕100,而出現"拉不到底部"的情況。
第二點的效果相比以前的automaticallyAdjustsScrollViewInsets
方案,可以說智能很多,因為當處于①情況時,哪怕你的scrollView的布局位置根本就沒被導航欄擋住,它都會給你調整64。然后你就發現莫名起妙內容就被下移了。
tableView.frame = CGRectMake(0, 80, self.view.short_width, self.view.short_height - 80)
tableView.backgroundColor = [UIColor orangeColor];
接下來我們再說回contentInsetAdjustmentBehavior
屬性的這四個值:
- 首先是
UIScrollViewContentInsetAdjustmentNever
,如名所示:就算你的ScrollView
超出了safeAreaInsets
,系統不會對你的scrollView.adjustedContentInset
做任何事情,即不作任何調整; -
UIScrollViewContentInsetAdjustmentAlways
: 只要超了安全區,就調整相應的超出值,調整的最大值不會超過安全區相應EdgeInsets方向的最大值,如剛剛上述第2點; -
UIScrollViewContentInsetAdjustmentScrollableAxes
:系統會根據ScrollView
的滾動方向來進行判斷,假設我只是一個橫向滾動的ScrollView
,那即便我的布局起點和高度值超過了self.view的安全區,那么系統也不會調整scrollView.adjustedContentInset
對應的top
與bottom
方向值,只可垂直方向滾動同理,直接設置scrollView.scrollEnabled = NO
也同理; -
UIScrollViewContentInsetAdjustmentAutomatic
:系統默認值。文檔上是這樣說的:
Similar to .scrollableAxes, but for backward compatibility will also adjust the top & bottom contentInset when the scroll view is owned by a view controller with automaticallyAdjustsScrollViewInsets = YES inside a navigation controller, regardless of whether the scroll view is scrollable
其實文檔已經說的很清楚了,它與UIScrollViewContentInsetAdjustmentScrollableAxes
行為相似,但是為了兼容以前①這種情況,即使scrollView是不可滾動,也會根據safeAreaInsets
超出范圍進行調整。(具體效果可以試著自己上手調試,這里就不貼代碼和示意圖了)。
關于剛才說的注意點二,我想補充的是,當出現表格過高(比如超出了100)而導致"拉不到底部"的情況時,你可以選擇額外設置tableView.contentInset
屬性,bottom
方向設為100,或者選擇修改self.additionalSafeAreaInsets
的屬性。前者影響tableView.adjustedContentInset
值,后者影響self.view.safeAreaInsets
。你會發現剛好是兩數之和,事實上adjustedContentInset
的值正是由contentSize
加上contentInsetAdjustmentBehavior
所調整的值。而self.view.safeAreaInsets
會在原來的基礎上,加上你的additionalSafeAreaInsets
。由于我們很少直接修改contentSize
,所以基本上tableView.adjustedContentInset
都是系統的調整值。
以上都是個人拙見,如果有誤的話歡迎朋友在評論中指出。還有點想說的是,蘋果可能本意是方便開發者,但事實上如果你對這些屬性的來龍去脈不太了解清楚的話,確實是挺不方便的。。。因此可能現在很多的人做法都是一開始就設置之前的automaticallyAdjustsScrollViewInsets
為NO,設置新的contentInsetAdjustmentBehavior
為UIScrollViewContentInsetAdjustmentNever
。就我個人看來,如果你需要實現類似系統默認那種表格穿透
半透明導航欄或者底部半透明TabBar的效果時,這個屬性使用起來就很舒服,直接tableView.frame = self.view.bouds 或者make.edges.equal.to(self.view)
就好了。而無需再設置額外的contentSize
。如果不需要類似的穿透,那可以選擇直接將其禁止。
① scroll view is owned by a view controller with automaticallyAdjustsScrollViewInsets = YES inside a navigation controller
PS:并且該scollView是第一個被添加的子視圖