Updating Your App for iOS 11 - Part2(Safe Area/ScrollView/TableView的新特性)

一甫题、Safe Area

從 iOS 7 開始派敷,我們就在操作系統(tǒng)里提供這樣的半透明的欄,并且鼓勵你把要顯示的內(nèi)容布局延伸過這些欄炕吸,就像下圖中照片 App 中做的那樣。(注意頂部和底部都帶有 Bar勉痴,且內(nèi)容都被 Bar 所覆蓋赫模,產(chǎn)生出模糊效果)


image.png

之所以又這樣的效果是利用了 UIViewController 的屬性 edgesForExtendedLayout,它可以讓作為 Container 的ViewControllers 定義這些(translucent bars)欄下View 的大小

edgesForExtendedLayout控制 View 的大小 讓 translucent bars 覆蓋其上之后帶有模糊效果

默認(rèn)情況下edgesForExtendedLayout 適用于所有的邊緣蒸矛,你可以通過topLayoutGuide 和 bottomLayoutGuide 兩個屬性來定義懸浮欄的大小瀑罗。

從 iOS 11開始,系統(tǒng)將取消topLayoutGuide 和 bottomLayoutGuide屬性雏掠,引入新的布局結(jié)構(gòu)概念斩祭,SafeArea。

取消topLayoutGuide 和 bottomLayoutGuide屬性 新的布局結(jié)構(gòu)概念乡话,SafeArea摧玫。

safeArea是描述你的視圖部分不被任何內(nèi)容遮擋的方法。 它提供兩種方式:safeAreaInsets 或 safeAreaLayoutGuide 來提供給你 safeArea 的參照值绑青,這兩個屬性定義在 UIView 中诬像,它們分別對應(yīng) insets 或者 layout guide類型。

例如在你自定義的 ViewController 中添加一些自定義的欄樣式 View闸婴,此時就需要改變 safeAreaInsets 的值坏挠。要想增加或減少safeAreaInsets的值,你可以通過調(diào)用 UIViewController 的新屬性 additionalSafeAreaInsets (UIEdgeInsets 類型)在對應(yīng)的位置增加 inset 值進(jìn)而改變 safeAreaInsets邪乍。當(dāng)你的viewController改變了它的safeAreaInsets值時降狠,有兩種方式獲取到回調(diào):

UIView.safeAreaInsetsDidChange()
UIViewController.viewSafeAreaInsetsDidChange()

每個 view 都可以改變 safeAreaInsets 的值对竣,包括 UIViewController。

image.png

二榜配、Scroll Views

下面例子中的結(jié)構(gòu)是 UIVIewController + UIScrollView 包在
UINavigationController 里面否纬。

以前如果一個 VIewController 中含有 ScrollView的話, 被
NavigationController 包住的這個 ViewController 會自動地調(diào)整 ScrollView 的 contentInset 值(增加64)如下

iOS 11之后這個行為已取消蛋褥,取而代之的是烦味,使用一個新的屬性adjustedContentInset代替。而 contentInset 這個屬性代表的概念簡單明了壁拉,單單是內(nèi)容的區(qū)域的 inset,不再與外界布局有關(guān)柏靶。

UIScrollView 支持自動布局弃理,讓scrollView可以根據(jù)所添加的sub-view的大小自動處理其可滾動區(qū)域的大小。iOS 11下更是添加了一些新的屬性來協(xié)助開發(fā)中更快速的布局屎蜓,其中包括 frameLayoutGuide 和 contentLayoutGuide 以及 contentInsetAdjustmentBehavior痘昌。

  1. frameLayoutGuide 負(fù)責(zé)scrollView在屏幕中的大小和位置,也就是你可以約束 scrollView 中的 sub-view 如下圖中的 Page 1 labelView炬转。當(dāng)你滾動時辆苔,該 page 1 labelview 是固定不動的。
約束 scrollView 中的 sub-view Page 1 labelView 當(dāng)內(nèi)容滾動后扼劈,Page 1 位置不變
  1. contentLayoutGuide驻啤,你可以約束 sub-view 來控制器 scrollView 中可滾動區(qū)域的大小或者讓內(nèi)容隨著滾動而移動。
指定 contentLayoutGuide 發(fā)生滾動時
  1. contentInsetAdjustmentBehavior屬性用來配置adjustedContentInset的行為荐吵,該結(jié)構(gòu)體有以下幾種類型:
typedef NS_ENUM(NSInteger, UIScrollViewContentInsetAdjustmentBehavior) {
    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, // Edges for scrollable axes are adjusted (i.e., contentSize.width/height > frame.size.width/height or alwaysBounceHorizontal/Vertical = YES)
    UIScrollViewContentInsetAdjustmentNever, // contentInset is not adjusted
    UIScrollViewContentInsetAdjustmentAlways, // contentInset is always adjusted by the scroll view's safeAreaInsets
} API_AVAILABLE(ios(11.0),tvos(11.0));
/* Configure the behavior of adjustedContentInset.
 Default is UIScrollViewContentInsetAdjustmentAutomatic.
 */
@property(nonatomic) UIScrollViewContentInsetAdjustmentBehavior contentInsetAdjustmentBehavior API_AVAILABLE(ios(11.0),tvos(11.0));
/* When contentInsetAdjustmentBehavior allows, UIScrollView may incorporate
 its safeAreaInsets into the adjustedContentInset.
 */
@property(nonatomic, readonly) UIEdgeInsets adjustedContentInset API_AVAILABLE(ios(11.0),tvos(11.0));

當(dāng)adjustedContentInset 值被改變后回調(diào)的代理方法有:

/* Also see -[UIScrollView adjustedContentInsetDidChange]
 */
- (void)scrollViewDidChangeAdjustedContentInset:(UIScrollView *)scrollView API_AVAILABLE(ios(11.0), tvos(11.0));

三骑冗、Table Views

  1. 我們知道在iOS 8引入Self-Sizing 之后,可以通過實現(xiàn)estimatedRowHeight 相關(guān)的屬性來展示動態(tài)的內(nèi)容先煎,當(dāng)實現(xiàn)了estimatedRowHeight 屬性后贼涩,tableview 會得到的初始 contenSize ,這是一個估算值薯蝎,是通過estimatedRowHeight * cell的個數(shù)得到的遥倦,并不是最終的 contenSize。

因為有估算的 contentSize 值占锯,所以tableView就不會一次性計算所有的cell的高度了袒哥,只會計算當(dāng)前屏幕能夠顯示的cell個數(shù)再加上幾個。

滑動時烟央,tableView 不停地得到新的 cell统诺,更新自己的 contenSize,在滑到最后的時候疑俭,會得到正確的 contenSize 粮呢。在測試Demo中,創(chuàng)建tableView 到顯示出來的過程中,contentSize 的計算過程如下圖:

  1. Self-Sizing
    在iOS 11中默認(rèn)啟用 Self-Sizing, 也就是說你 cell啄寡、header豪硅、footer對應(yīng)的 estimated heights 默認(rèn)值都從 iOS 11 之前的0 變?yōu)閁ITableViewAutomaticDimension。
    因為默認(rèn)開啟了 Self-Sizing挺物,你在布局 cell 時需要確保內(nèi)部子控件具備完整約束來讓 tableview 自動計算出其需要的大小或者你在對應(yīng)的 delegate 方法中返回每一個 cell 的真實高度值懒浮。同理也需要處理對應(yīng) header 和 footer 問題。

如果目前項目中沒有使用estimateRowHeight屬性识藤,在iOS11的環(huán)境下就要注意了砚著,因為開啟Self-Sizing之后,tableView是使用estimateRowHeight屬性的痴昧,這樣就會造成contentSize和contentOffset值的變化稽穆,如果是有動畫是觀察這兩個屬性的變化進(jìn)行的,就會造成動畫的異常赶撰,因為在估算行高機制下舌镶,contentSize的值是一點點地變化更新的,所有cell顯示完后才是最終的contentSize值豪娜。因為不會緩存正確的行高餐胀,tableView reloadData的時候,會重新計算contentSize瘤载,就有可能會引起contentOffset的變化否灾。

如果你想 link 到 iOS 11 而不想使用這個默認(rèn)開啟的新特性(Self-Sizing)的話,你可以取消它鸣奔,代碼如下:

override func viewDidLoad() {
//取消 estimated sizes 功能和 tableview 的 Self-Sizing 功能
 tableView.estimatedRowHeight = 0
 tableView.estimatedSectionHeaderHeight = 0
 tableView.estimatedSectionFooterHeight = 0
}

iOS11下坟冲,如果沒有設(shè)置estimateRowHeight的值,也沒有設(shè)置rowHeight的值溃蔫,那contentSize計算初始值是 44 * cell的個數(shù)健提,如下圖:rowHeight和estimateRowHeight都是默認(rèn)值UITableViewAutomaticDimension 而rowNum = 15;則初始contentSize = 44 * 15 = 660伟叛;

  1. separatorInset
    tableView 的 readable content guide 概念私痹,它是 View 內(nèi)的一部分,也是內(nèi)容布局的推薦區(qū)域统刮。即使在大屏幕的 iPad 下紊遵,在 readable content guide 內(nèi)布局的內(nèi)容都能夠獲得不錯的用戶閱讀體驗。

默認(rèn)情況下 tableview 在 readable content guide 內(nèi)有一個 separatorInset侥蒙,它可以影響 cell 的默認(rèn)分隔線位置 和 在 cell 內(nèi) labels 的位置暗膜。

separator.left = 0 separator.left = 30

可見 separatorInset 是對 readable content view 的 inset 處理。

iOS 11 之后鞭衩,separatorInset 值影響的是学搜,tableview 邊框與屏幕的邊緣的間隔大小娃善,當(dāng)設(shè)置左右為0時,效果如下

iPad 橫屏下瑞佩,separatorInset.left = 0 和 separatorInset.right = 0

如下是 separatorInset 值使用對別聚磺,其中在 iOS 11后添加可設(shè)置參照的屬性UITableViewSeparatorInsetReference

typedef NS_ENUM(NSInteger, UITableViewSeparatorInsetReference) {  
UITableViewSeparatorInsetFromCellEdges,   //默認(rèn)值,表示separatorInset是從cell的邊緣的偏移量
UITableViewSeparatorInsetFromAutomaticInsets  //表示separatorInset屬性值是從一個insets的偏移量
}

對比使用如下:

UITableViewSeparatorInsetFromCellEdges UITableViewSeparatorInsetFromAutomaticInsets
  1. tableview 與 Safe Area 交互需要注意幾點:
  • separatorInset 被自動地關(guān)聯(lián)到 safe area insets炬丸,因此瘫寝,默認(rèn)情況下,tabelview的整個內(nèi)容區(qū)域避免了ViewController安全區(qū)域的插入稠炬。
  • UITableviewCell 和 UITableViewHeaderFooterView的 content view 在安全區(qū)域內(nèi)焕阿;因此你應(yīng)該始終在 content view 中使用add-subviews操作
  • 你應(yīng)該使用帶有 content view 的 UITableViewHeaderFooterView類實例作為table headers 和 footers、section headers 和 footers首启。
  1. Swipe Actions
    1. 新的滾動條:帶有 time stamps 時碼的滾動條
    2. 實現(xiàn) full swipe-to-delete 功能
    3. 添加了又滑功能

測試默認(rèn)開啟Self-Sizing的 iOS 11問題捣鲸。

問題1:如下代碼是運行在 iOS 10下正常,但運行在 iOS 11則在 tabelView 上下有留白問題
//
//  ViewController.m
//  ios10TabelView
//
//  Created by Jacob_Liang on 2017/9/21.
//  Copyright ? 2017年 Jacob. All rights reserved.
//

#import "ViewController.h"

static NSString * const CELLID = @"CELLID";

@interface ViewController ()<UITableViewDelegate, UITableViewDataSource>

@property (nonatomic, weak) UITableView *tableView;

@end

@implementation ViewController


- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self setUpInit];
    [self setUpNav];
    [self setUpTableView];
    
}

- (void)setUpInit {

    self.automaticallyAdjustsScrollViewInsets = NO; //iOS 11下被廢棄了闽坡,寫了也沒用
    self.view.backgroundColor = [UIColor purpleColor];
}

- (void)setUpNav {
    self.navigationItem.title = @"出席統(tǒng)計";
}

- (void)setUpTableView {
    
    CGFloat screenW = [UIScreen mainScreen].bounds.size.width;
    CGFloat screenH = [UIScreen mainScreen].bounds.size.height;
    
    UITableView *tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 64, screenW, screenH - 64) style:UITableViewStyleGrouped];
    [self.view addSubview:tableView];
    _tableView = tableView;
    tableView.backgroundColor = [UIColor lightGrayColor];
    tableView.delegate = self;
    tableView.dataSource = self;
    
    [tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:CELLID];

}

#pragma mark - UITableViewDelegate & UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 15;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CELLID forIndexPath:indexPath];
    cell.textLabel.text = [NSString stringWithFormat:@"%@",indexPath];
    return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return 50;
}

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
    return 0.01;
}

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
    return 0.01;
}

@end

上述代碼運行情況,注意此時 tableview 的 Style 為 UITableViewStyleGrouped

在 iOS 10 下 iOS 11下 iOS 11下
self.automaticallyAdjustsScrollViewInsets = NO 有效 self.automaticallyAdjustsScrollViewInsets = NO 無效 self.automaticallyAdjustsScrollViewInsets = NO 無效
沒有調(diào)用viewForFooterInSection和viewForHeaderInSection運行正常 沒有調(diào)用viewForFooterInSection和viewForHeaderInSection運行有留白 調(diào)用viewForFooterInSection和viewForHeaderInSection運行正常
iOS10NOReturnViewFooterHeader.gif
NOReturnHeaderOrFooterViewQuestion.gif
wihtReturnHeaderOrFooterView.gif

另一宗辦法就是愁溜,關(guān)閉 iOS 11默認(rèn)打開的 Self-Sizing 功能

    tableView.estimatedRowHeight = 0;
    tableView.estimatedSectionFooterHeight = 0;
    tableView.estimatedSectionHeaderHeight = 0;

問題1測試 demo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末疾嗅,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子冕象,更是在濱河造成了極大的恐慌代承,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件渐扮,死亡現(xiàn)場離奇詭異论悴,居然都是意外死亡,警方通過查閱死者的電腦和手機墓律,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門膀估,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人耻讽,你說我怎么就攤上這事察纯。” “怎么了针肥?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵饼记,是天一觀的道長。 經(jīng)常有香客問我慰枕,道長具则,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任具帮,我火速辦了婚禮博肋,結(jié)果婚禮上低斋,老公的妹妹穿的比我還像新娘。我一直安慰自己束昵,他們只是感情好拔稳,可當(dāng)我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著锹雏,像睡著了一般巴比。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上礁遵,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天轻绞,我揣著相機與錄音,去河邊找鬼佣耐。 笑死政勃,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的兼砖。 我是一名探鬼主播奸远,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼讽挟!你這毒婦竟也來了懒叛?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤耽梅,失蹤者是張志新(化名)和其女友劉穎薛窥,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體眼姐,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡诅迷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了众旗。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片罢杉。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖贡歧,靈堂內(nèi)的尸體忽然破棺而出屑那,到底是詐尸還是另有隱情,我是刑警寧澤艘款,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布持际,位于F島的核電站,受9級特大地震影響哗咆,放射性物質(zhì)發(fā)生泄漏蜘欲。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一晌柬、第九天 我趴在偏房一處隱蔽的房頂上張望姥份。 院中可真熱鬧郭脂,春花似錦、人聲如沸澈歉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽埃难。三九已至莹弊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間涡尘,已是汗流浹背忍弛。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留考抄,地道東北人细疚。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像川梅,于是被迫代替她去往敵國和親疯兼。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容

  • iOS 11 為整個生態(tài)系統(tǒng)的 UI 元素帶來了一種更加大膽贫途、動態(tài)的新風(fēng)格吧彪。 本文介紹iOS11中在UI方面做了哪...
    阿凡提說AI閱讀 590評論 0 1
  • 版權(quán)聲明:未經(jīng)本人允許,禁止轉(zhuǎn)載. 1. TableView初始化 1.UITableView有兩種風(fēng)格:UITa...
    蕭雪痕閱讀 2,908評論 2 10
  • 我們在上一篇《通過代碼自定義不等高cell》中學(xué)習(xí)了tableView的相關(guān)知識,本文將在上文的基礎(chǔ)上潮饱,利用sto...
    啊世ka閱讀 1,508評論 2 7
  • 人心里的悲觀,只不過是他見到了陰暗給眼前的坎诫给,心生恐懼香拉;又遭遇了黑暗給人生存的艱難,意志消沉中狂。 ...
    汩月閱讀 713評論 0 0
  • 下午放學(xué)時候凫碌,女兒得意的告訴我,數(shù)學(xué)考試得了110分胃榕,滿分盛险。緊接著愁眉苦臉說,可是明天她們要考英語勋又,她的英語總是考...
    彭曉芬閱讀 243評論 0 3