前言:
xcode升級到9.0以后,對應的模擬器也升級到了ios11.0,框架中屬性有了一些改變,提出了一些新的概念,但這個概念如果決定到了系統的適配,是必須要搞懂的,因為舊低版本系統中一些屬性的設置已經不適用于最新的系統,比如safeArea,看了別人的文章自己還是沒有徹底搞清楚,不如自己去一點點分析來的透徹,寫的比較詳細,請提出寶貴建議,本菜鳥愿與大家一起進階!
開始:
本文研究的視圖層次結構:控制器view上添加scrollview,scrollview上再添加tableview,最后給view上添加標題欄,最外面還有狀態欄和導航欄,對這個結構因為自己很熟悉了,所以不上圖了
原因:很常用并且很有代表性
發現的問題:xcode升級到9.x以后,要實現tableview中的cell能夠穿越整個屏幕,就要設置一個內邊距,即可滾動區域,三步曲:對加到控制器view上的scrollview,利用控制器屬性automaticallyAdjustsScrollViewInsets取消系統設置的內邊距,設置了tableview的y值為0,讓它占滿整個屏幕,再設置tableview的內邊距值為(64+35,0,49,0),然后在ios11模擬器上運行后發現跟之前的系統不一樣了,第一個cell想對于標題欄多下降了一個64的高度,往上拉,最后一個cell多上了49的內邊距,設置內邊距,ios11只需要(35,0,0,0),這里的35指標題欄的高度
分析:
為什么會出現這個問題呢?
對比分析可知,原先需要手動給tableview多調節64的內邊距,而現在不需要了,系統的某個屬性幫做了,而自己手動設置的contentInset屬性上方35仍然起作用,意思就是說原先tableview的contentInset就可以完全決定內容cell的顯示區域,現在得配合另一個屬性才能夠決定。
當時的困惑:這個屬性一定是系統新增的,它到底是什么?為什么要引入這個屬性?如何做這種系統適配?
測試分析:
準備工作:先在xcode中下載了ios9.3,用于對比,在viewDiaAppear方法中進行打印測試,而不是在viewDidLoad中,因為viewDiaAppear方法調用時,對應的view已經顯示好了,已經判斷出了前方有沒有導航欄和狀態欄,決定它顯示范圍的內邊距屬性已經起了作用,這時打印才會有值
條件控制屬性:contentInsetAdjustmentBehavior和automaticallyAdjustsScrollViewInsets對比,我把這些控制條件的叫做條件控制屬性,能夠獲取值的叫做值屬性,這樣概念比較清晰
automaticallyAdjustsScrollViewInsets是屬于控制器對象的屬性,而contentInsetAdjustmentBehavior是屬于scrollview或者tableview的屬性,ios11廢棄了automaticallyAdjustsScrollViewInsets屬性,用contentInsetAdjustmentBehavior來代替,個人覺得這樣是很好的,誰的事情誰管理,以前,盡管控制器對象把它的屬性設置為NO,就能控制scrollview中的tableview范圍不被壓縮,tableview中的cell也不會被壓縮,但是現在不同了,各管理各的
ios11?
scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever
ios9?
self.automaticallyAdjustsScrollViewInsets = NO
看資料后發現,發現系統給tableview或者scrollview新增兩個屬性adjustedcontentInset,safeAreaInsets
對比測試:tableview添加到scrollview上后
1.先不設置tableview內邊距,在ios11.0上運行,contentInset打印之后上下左右為0,明明cell已經下移了啊,系統已經給tableview中的內容設置了內邊距,按理說它應該是有值的,怎么 會是0,如果在ios9.3中,它絕對不會是0,{64, 0, 49, 0},原先它是能反映出系統的自動調整的,前后一對比,升級到11.0以后,說明這個contentInset屬性已經不再能反映出系統的調整行為了,不能作為代表了,能夠代表系統的可能換了屬性了,換成哪個屬性了呢?是safeAreaInsets還是adjustedContentInset,經過打印測試,結果都為{64, 0, 49, 0},這就奇怪了
2.當給tableview設置contentInset后,self.tableView.contentInset = UIEdgeInsetsMake(35, 0, 49, 0);
再次測試打印,self.tableView.contentInset:{35, 0, 49, 0}
self.tableview.safeAreaInsets:{64, 0, 49, 0}
self.tableview.adjustedcontentInset:{99, 0, 98, 0}
adjustedcontentInset =?contentInset +?safeAreaInsets
說明了什么呢?
說明了safeAreaInsets可能是一個恒定的值,是一個標準值,是根據系統中有無導航欄和tabBar來判斷,它的值是系統給設定的,最終能夠反映tableview中內容下移多少的的只能是adjustedcontentInset屬性,它的屬性值是其余兩個屬性值的相加
那么問題又來了,既然adjustedcontentInset是真正反映內邊距是多少的,那么直接設置這個屬性就可以了啊,那么能不能設置呢?
經過測試是不能的,因為它是一個只讀屬性,這個在它的屬性定義標簽里面也能看到,那么ios11引入這個屬性有何用,只能看不能設置?是的,它只能看不能設置,它的只能利用另外兩個屬性的值相加
繼續研究相對的問題:
safeAreaInsets是safearea安全區域相對于tableview邊緣
contentInset是相對于safeArea安全區域
adjustedcontentInset是相對于tableview邊緣
真正能反映tableview中內容的內邊距是adjustedcontentInset
探討safearea安全區域
ios11為什么要引入safeArea呢?
蘋果專門為了iphoneX設備的劉海和下方的欄而改進的系統,提出了safeArea,目的就是為了無論橫屏還是豎屏,顯示的內容會居中,因為屏幕是不規則的,可以認為系統和設備是兩個相對獨立的概念,卻又彼此聯系,既然設備屏幕是不規則的,這是一個沒法改變的事情,而系統規則是可以靈活定義的,只能改變系統了,為了內容的正常顯示,系統里面的規則必須要向設備妥協,這本身是一個最好的選擇,改變環境不如改變自己,但前提是這個設備不應該違反視覺美學
safearea到底是什么?
它并不是一個對象,可以認為是一個規定的顯示范圍,以前,只要scrollview中的內容前面有導航欄和狀態欄,系統直接動手,馬上把你壓下去,而現在系統直接給你劃分了區域,做了規范,你只能在這個區域顯示
這個安全區域的范圍能否改變呢?哪個屬性才能調整它呢?
可以改變,additionalSafeAreaInsets這個屬性可以調整safeAreaInset的指
總結:
scrollview中的內容下移的距離,由adjustedContentInset決定
adjustedContentInset中的x表示scrollview中的內容左上角相對于scrollview的左上角偏移的距離,計算方式由scrollview條件控制屬性contentInsetAdjustmentBehavior決定,主要討論兩種計算方式:
1.默認情況
UIScrollViewContentInsetAdjustmentAutomatic
公式:adjustedcontentInset =?contentInset +?safeAreaInsets
這種情況下,就要考慮contentInset的取值了
2.手動禁止調整內邊距
UIScrollViewContentInsetAdjustmentNever
這種情況雖然打印安全區域內邊距有值,安全區域依然存在,但是它已經不參與計算了
公式:adjustedContentInset = contentInset
適配:
豎屏情況下,不管是哪種設備,哪種系統,如果想做到很靈活的解決內容顯示不會發生偏移,只有手動話控制才能隨心所欲,始終按自己的想法來,一旦有系統的自動化調節參與進來,就很麻煩,分各種情況考慮,所以把系統的自動調整行為完全禁止掉,自己手動設置contentInset,在scrollview初始化方法和tableview控制器的viewDidLoad中各寫一份不同系統下的適配禁止行為,在tableview控制器viewDidLoad方法中只寫一份contentInset設置,取值都一樣
if(@available(iOS11.0, *)) {
? ? ? ? self.tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
? ? }else{
? ? ? ? self.automaticallyAdjustsScrollViewInsets = NO;
?? ?}
注意:以前取值用常量,但是現在取值不要用常量,最好還是用宏代替,特別是系統欄的值,用方法獲取系統導航欄,狀態欄的高度,因為iphoneX中狀態欄的高度變為了44,而不是20了,自定義的標題欄高度可以用常量