iOS中safe area對scrollView的內(nèi)容偏移產(chǎn)生的影響(iOS11的適配問題)

scrollview的幾個關鍵屬性

contentSize: 就是scrollView可以滾動的區(qū)域. 例如 frame = (0,0, 320, 480), contentSize = (320, 960), 代表scrollView可以上下滾動, 滾動區(qū)域為frame大小的兩倍.

contentOffset 是scrollview當前顯示區(qū)域頂點相對于frame頂點的偏移量, 比如上一個例子中, 將scrollView拉到最下面, 那么contentOffset = (0, 480), 也就是 y 偏移了480.

contentInset是scrollView中的contentView.frame.originscrollView.frame.origin之間的關系. 例如contentView.frame = (0, 30, 320, 480), 那么contentInset = (0, 30)

iOS11 新加入的屬性 adjustedContentInset: 表示scrollView的內(nèi)容的自適應內(nèi)邊距, 它的取值和contentInsetAdjustmentBehavior枚舉屬性息息相關, 同時取消vc.automaticallyAdjustsScrollViewInsets屬性值.

scrollView關鍵屬性的實踐(一)

vc在navigationController中, navigationBar是默認狀態(tài), 并且self.automaticallyAdjustsScrollViewInsets = YESscrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentAutomatic;都是使用的默認值.(注意如果當前vc沒有在navigationController或者TabbarController中時候, 結果可能不一樣, 我們一般討論的是scrollView在navigationController中的情況)

-(void)viewDidLoad{
    UIScrollView *scrollView = [[UIScrollView alloc] init];
    scrollView.backgroundColor = [UIColor whiteColor];
    [self.view addSubview:scrollView];
    scrollView.frame = self.view.bounds;
    scrollView.contentSize = CGSizeMake(self.view.bounds.size.width, self.view.bounds.size.height * 2);
    self.scrollView = scrollView;

    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    [scrollView addSubview:button];
    button.frame = CGRectMake(0, 0, 100, 100);
    button.backgroundColor = [UIColor grayColor];
    [button addTarget:self action:@selector(buttonDidClick) forControlEvents:UIControlEventTouchUpInside];
    if (@available(iOS 11.0, *)) {
        scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentAutomatic;
    } else {
        self.automaticallyAdjustsScrollViewInsets = YES;
    }
}
在iOS8上:
2018-09-27 14:49:13.103 scrollViewInVcDemo[56036:1691899] contentInset: {64, 0, 0, 0}
2018-09-27 14:49:13.103 scrollViewInVcDemo[56036:1691899] contentOffset: {0, -64}

在iOS11上:
2018-09-27 14:47:23.731497+0800 scrollViewInVcDemo[55894:1682631] contentInset: {0, 0, 0, 0}
2018-09-27 14:47:23.731605+0800 scrollViewInVcDemo[55894:1682631] contentOffset: {0, -64}
2018-09-27 14:47:23.731708+0800 scrollViewInVcDemo[55894:1682631] safeArea: {64, 0, 0, 0}
2018-09-27 14:47:23.731867+0800 scrollViewInVcDemo[55894:1682631] adjustedContentInset: {64, 0, 0, 0}

最終界面展示是一致的, 正方形的button 位于界面的左上方, navBar下:

image.png

上述代碼中, 如果設置self.navigationController.navigationBar.hidden = YES;, 得到的結果如下:

iOS8:
2018-09-27 15:16:04.581 scrollViewInVcDemo[57368:1792003] contentInset: {20, 0, 0, 0}
2018-09-27 15:16:04.581 scrollViewInVcDemo[57368:1792003] contentOffset: {0, -20}

iOS11:
2018-09-27 15:16:56.342570+0800 scrollViewInVcDemo[57444:1799639] contentInset: {0, 0, 0, 0}
2018-09-27 15:16:56.342685+0800 scrollViewInVcDemo[57444:1799639] contentOffset: {0, -20}
2018-09-27 15:16:56.342787+0800 scrollViewInVcDemo[57444:1799639] safeArea: {20, 0, 0, 0}
2018-09-27 15:16:56.342894+0800 scrollViewInVcDemo[57444:1799639] adjustedContentInset: {20, 0, 0, 0}
image.png

可以得出結論:

  1. iOS10以前通過設置self.automaticallyAdjustsScrollViewInsets = YES;可以改變scrollView的contentInset, 從而使得scrollView上的元素不會被navigationBar或者tabbar遮擋.
  2. 在iOS11以后.則通過設置contentInsetAdjustmentBehavior屬性來改變adjustedContentInset屬性, 來完成相同效果, 同時contentInset屬性并未修改.并且automaticallyAdjustsScrollViewInsets屬性失效.

scrollView關鍵屬性的實踐(二)

如果我們設置如下關鍵屬性:

    self.navigationController.navigationBar.hidden = NO;
    if (@available(iOS 11.0, *)) {
        scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
    } else {
        self.automaticallyAdjustsScrollViewInsets = NO;
    }

得到的結論如下:

/**
 iOS 8:
 2018-10-08 16:30:31.331 scrollViewInVcDemo[3018:165133] scrollView: <UIScrollView: 0x7fddcec31390; frame = (0 0; 375 667); clipsToBounds = YES; gestureRecognizers = <NSArray: 0x7fddcec32050>; layer = <CALayer: 0x7fddcec318c0>; contentOffset: {0, 0}; contentSize: {375, 1334}>
 2018-10-08 16:30:31.331 scrollViewInVcDemo[3018:165133] contentInset: {0, 0, 0, 0}
 2018-10-08 16:30:31.332 scrollViewInVcDemo[3018:165133] contentOffset: {0, 0}

 iOS 11:
 2018-10-08 16:36:40.084890+0800 scrollViewInVcDemo[3252:188595] scrollView: <UIScrollView: 0x7ffd2d837000; frame = (0 0; 375 667); clipsToBounds = YES; gestureRecognizers = <NSArray: 0x60000097a8b0>; layer = <CALayer: 0x6000007447a0>; contentOffset: {0, 0}; contentSize: {375, 1334}; adjustedContentInset: {0, 0, 0, 0}>
 2018-10-08 16:36:40.085049+0800 scrollViewInVcDemo[3252:188595] contentInset: {0, 0, 0, 0}
 2018-10-08 16:36:40.085251+0800 scrollViewInVcDemo[3252:188595] contentOffset: {0, 0}
 2018-10-08 16:36:40.085379+0800 scrollViewInVcDemo[3252:188595] safeArea: {64, 0, 0, 0}
 2018-10-08 16:36:40.085521+0800 scrollViewInVcDemo[3252:188595] adjustedContentInset: {0, 0, 0, 0}
 */

兩者結果都如下圖:

image.png

可以得出結論:

  1. iOS10以前通過設置self.automaticallyAdjustsScrollViewInsets = NO ;與在iOS11以后設置contentInsetAdjustmentBehavior=UIScrollViewContentInsetAdjustmentNever屬性是等效的.

  2. contentInsetAdjustmentBehavior=UIScrollViewContentInsetAdjustmentNever屬性時候會有如下關系: adjustedContentInset == contentInset

iOS11以后, contentInsetAdjustmentBehavioradjustedContentInset的關系

  1. UIScrollViewContentInsetAdjustmentAutomatic:
    如果scrollview在一個automaticallyAdjustsScrollViewContentInset = YES的controller上仇冯,并且這個Controller包含在一個navigationController中咒循,這種情況下會設置在top & bottom上 adjustedContentInset = safeAreaInset + contentInset(不管是否滾動)。其他情況下與UIScrollViewContentInsetAdjustmentScrollableAxes相同.
  2. UIScrollViewContentInsetAdjustmentScrollableAxes:
    在可滾動方向上adjustedContentInset = safeAreaInset + contentInset埃撵,在不可滾動方向上adjustedContentInset = contentInset;依賴于scrollEnabled和alwaysBounceHorizontal / vertical = YES卧晓,scrollEnabled默認為yes贞远,所以大多數(shù)情況下,計算方式還是adjustedContentInset = safeAreaInset + contentInset.
  3. UIScrollViewContentInsetAdjustmentNever:
    adjustedContentInset = contentInset
  4. UIScrollViewContentInsetAdjustmentAlways:
    adjustedContentInset = safeAreaInset + contentInset

iOS中的安全區(qū)與additionalSafeAreaInsets

http://www.reibang.com/p/efbc8619d56b中提到:

在iOS 11以后 Controller的automaticallyAdjustsScrollViewInsets屬性被廢棄了瓢捉,所以當tableView超出安全區(qū)域時系統(tǒng)自動調(diào)整了SafeAreaInsets值频丘,進而影響adjustedContentInset值,在iOS 11中決定tableView的內(nèi)容與邊緣距離的是adjustedContentInset屬性泡态,而不是contentInset搂漠。adjustedContentInset的計算方式見本文第二部分內(nèi)容。因為系統(tǒng)對adjustedContentInset值進行了調(diào)整某弦,所以導致tableView的內(nèi)容到邊緣的距離發(fā)生了變化桐汤,導致tableView下移了20pt(statusbar高度)或64pt(navigationbar高度)。

如果你的APP中使用的是自定義的navigationbar靶壮,隱藏掉系統(tǒng)的navigationbar怔毛,并且tableView的frame為(0,0,SCREEN_WIDTH, SCREEN_HEIGHT)開始,那么系統(tǒng)會自動調(diào)整SafeAreaInsets值為(20,0,0,0)亮钦,如果使用了系統(tǒng)的navigationbar馆截,那么SafeAreaInsets值為(64,0,0,0),如果也使用了系統(tǒng)的tabbar蜂莉,那么SafeAreaInsets值為(64,0,49,0)蜡娶。關于什么情況下會發(fā)生內(nèi)容下移的問題,本文第三部分有介紹映穗。

image.png

在iOS7中Apple引入的UIViewController的topLayoutGuidebottomLayoutGuide屬性, 他們可以讓我們創(chuàng)建約束已避免內(nèi)容被UIKit的橫條, 狀態(tài)欄, 導航或者標簽欄覆蓋, 現(xiàn)在在iOS11中全部被被廢棄, 并且由安全區(qū)替代.

viewController在iOS11中添加了一個新的屬性additionalSafeAreaInsets, 通過該屬性, 我們可以規(guī)定我們自己的safe ares insets, 最終系統(tǒng)根據(jù)我們設置的additionalSafeAreaInsets 以及 adjustedContentInset, 系統(tǒng)會計算出最終的 safe area.

注意: 如果viewController是在navigationController中, 那么應該先修改NavigationController的additionalSafeAreaInsets, 然后再改變viewControlleradditionalSafeAreaInsets.

建議仔細讀一下下面的參考資料, 騰訊 bugly 寫的文章非常棒

參考資料

iOS 11 安全區(qū)域適配總結
適配iOS11--contentInsetAdjustmentBehavior

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末窖张,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蚁滋,更是在濱河造成了極大的恐慌宿接,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件辕录,死亡現(xiàn)場離奇詭異睦霎,居然都是意外死亡,警方通過查閱死者的電腦和手機走诞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門副女,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蚣旱,你說我怎么就攤上這事碑幅〈鞫福” “怎么了?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵沟涨,是天一觀的道長恤批。 經(jīng)常有香客問我,道長裹赴,這世上最難降的妖魔是什么喜庞? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮篮昧,結果婚禮上赋荆,老公的妹妹穿的比我還像新娘笋妥。我一直安慰自己懊昨,他們只是感情好,可當我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布春宣。 她就那樣靜靜地躺著酵颁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪月帝。 梳的紋絲不亂的頭發(fā)上躏惋,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天,我揣著相機與錄音嚷辅,去河邊找鬼簿姨。 笑死,一個胖子當著我的面吹牛簸搞,可吹牛的內(nèi)容都是我干的扁位。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼趁俊,長吁一口氣:“原來是場噩夢啊……” “哼域仇!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起寺擂,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤暇务,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后怔软,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體垦细,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年挡逼,在試婚紗的時候發(fā)現(xiàn)自己被綠了括改。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡挚瘟,死狀恐怖叹谁,靈堂內(nèi)的尸體忽然破棺而出饲梭,到底是詐尸還是另有隱情,我是刑警寧澤焰檩,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布憔涉,位于F島的核電站,受9級特大地震影響析苫,放射性物質(zhì)發(fā)生泄漏兜叨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一衩侥、第九天 我趴在偏房一處隱蔽的房頂上張望国旷。 院中可真熱鬧,春花似錦茫死、人聲如沸跪但。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽屡久。三九已至,卻和暖如春爱榔,著一層夾襖步出監(jiān)牢的瞬間被环,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工详幽, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留筛欢,地道東北人。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓唇聘,卻偏偏與公主長得像版姑,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子雳灾,可洞房花燭夜當晚...
    茶點故事閱讀 44,781評論 2 354