iOS 11適配:contentInsetAdjustmentBehavior解析

之前寫過一篇文章描述了下影響頁面布局的幾個屬性,如今iOS 11出來后變化挺大的,在這里重新梳理下。

01.png

可以看到在iOS 11中,UIViewController的automaticallyAdjustsScrollViewInsets屬性被棄用了,系統推薦我們使用UIScrollViewcontentInsetAdjustmentBehavior屬性替代之。關于這個屬性,系統提供了四種行為模式:

UIScrollViewContentInsetAdjustmentAutomatic
UIScrollViewContentInsetAdjustmentScrollableAxes
UIScrollViewContentInsetAdjustmentNever
UIScrollViewContentInsetAdjustmentAlways

第3、4種看起來比較清晰,要么不調整,要么"一直"調整。但估計不少朋友看到第1、2種會一臉懵逼,包括第4種里“一直”這個詞。在這解釋之前我們先分析下為什么automaticallyAdjustsScrollViewInsets會被棄用。

在我看來原因可能之前使用automaticallyAdjustsScrollViewInsets的方案太單調粗暴了。回顧以前所說的,當處于 ①(文末)情況時的scrollView,系統會自動修改其contentInset屬性,舉個例子:如果存在狀態欄導航欄,則contentInsettop值則會被修改為64,內容自動下移64。當底部存在系統UITabBar時,則bottom值修改為49,即下方額外增加49的滾動距離。

我們知道iOS 11后引入了安全區的概念safeAreaInsets

02.jpg

以不帶UITabBariPhone X為例:NavigationController的rootViewController.view(以下用self代稱該rootViewController),其safeAreaInsets{88, 0, 34, 0},在contentInsetAdjustmentBehavior屬性出現之前,系統是根據①情況進行的調整。而現在,系統將會根據ScrollView視圖大小(包括其類族UITableView等)是否超過了安全區來進行調整,需要注意的有兩點:

  1. 這個"調整"不再是直接修改scrollView.contentSize,而是scrollView.adjustedContentInset
  2. 調整的值將根據具體超出多少值來確定,但最大值不能超過安全區的相應EdgeInsets方向的值。以self.view的safeAreaInsets{88, 0, 34, 0}為例。此時添加一個tableView,其高度為self.view.short_height + 25,那么tableView.adjustedContentInsetbottom則為25。但如果超出高度為134,bottom最高也只會是34,這樣就會由于表格高度超過屏幕100,而出現"拉不到底部"的情況。

第二點的效果相比以前的automaticallyAdjustsScrollViewInsets方案,可以說智能很多,因為當處于①情況時,哪怕你的scrollView的布局位置根本就沒被導航欄擋住,它都會給你調整64。然后你就發現莫名起妙內容就被下移了。

內容被下移64.PNG
tableView.frame = CGRectMake(0, 80, self.view.short_width, self.view.short_height - 80)
tableView.backgroundColor = [UIColor orangeColor];

接下來我們再說回contentInsetAdjustmentBehavior屬性的這四個值:

  1. 首先是UIScrollViewContentInsetAdjustmentNever,如名所示:就算你的ScrollView超出了safeAreaInsets,系統不會對你的scrollView.adjustedContentInset做任何事情,即不作任何調整;
  2. UIScrollViewContentInsetAdjustmentAlways: 只要超了安全區,就調整相應的超出值,調整的最大值不會超過安全區相應EdgeInsets方向的最大值,如剛剛上述第2點;
  3. UIScrollViewContentInsetAdjustmentScrollableAxes:系統會根據ScrollView的滾動方向來進行判斷,假設我只是一個橫向滾動的ScrollView,那即便我的布局起點和高度值超過了self.view的安全區,那么系統也不會調整scrollView.adjustedContentInset對應的topbottom方向值,只可垂直方向滾動同理,直接設置scrollView.scrollEnabled = NO也同理;
  4. 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,設置新的contentInsetAdjustmentBehaviorUIScrollViewContentInsetAdjustmentNever。就我個人看來,如果你需要實現類似系統默認那種表格穿透半透明導航欄或者底部半透明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是第一個被添加的子視圖

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容