[iOS開發(fā)]UITableView的分割線設(shè)置及不能全屏原因

一般TableView設(shè)置全屏分隔線有下面三種方法

方法1:自定義cell, 手動添加分割線

  • 首先先隱藏系統(tǒng)自帶的分割線, 接下來有2種做法 (建議使用做法a)
    tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    或者
    self.tableView.separatorColor = [UIColor clearColor];

  • 做法a: 可以通過addSubview的方式添加一條分割線

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId forIndexPath:indexPath]; 
    
    //自定義分割線方法一: 通過addSubview的方式添加一條分割線
    //在自定義cell 里面給每個(gè)cell添加高度為2的紅色分割線
    CGFloat cellH = cell.frame.size.height;
    if(indexPath.row != cars.count - 1){
        UIView *line = [[UIView alloc] initWithFrame:CGRectMake(0, cellH-2, self.view.frame.size.width, 2)];
        line.backgroundColor = [UIColor redColor];
        [cell addSubview:line];
    }
    return cell;
}
  • 做法b:也可以自定義cell, cell中重寫drawRect: 自繪分割線
// 自繪分割線
- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
    CGContextFillRect(context, rect);
    
    CGContextSetStrokeColorWithColor(context, [UIColor greenColor].CGColor);
  //繪制高度為2綠色分割線
    CGContextStrokeRect(context, CGRectMake(0, rect.size.height - 2, rect.size.width, 2));
}

方法2:自定義cell , 重寫setFrame方法,cell高度-1,露出tableView背景色

  • 首先隱藏系統(tǒng)分割線, 設(shè)置tableView背景顏色.
self.tableView.separatorStyle =  UITableViewCellSeparatorStyleNone;
    // 設(shè)置tableView背景色
self.tableView.backgroundColor = [UIColor colorWithWhite:215 / 255.0 alpha:1];
  • 在自定義cell中重寫setFrame:
- (void)setFrame:(CGRect)frame
{
    frame.size.height -= 1;
    // 給cellframe賦值
    [super setFrame:frame];
}

方法3.利用系統(tǒng)屬性設(shè)置(separatorInset, layoutMargins), 共需添加四行代碼

  • 對tableView的separatorInset, layoutMargins屬性的設(shè)置
-(void)viewDidLoad {
    [super viewDidLoad];
    //1.調(diào)整(iOS7以上)表格分隔線邊距
    if ([self.tableView respondsToSelector:@selector(setSeparatorInset:)]) {
        self.tableView.separatorInset = UIEdgeInsetsZero;
    }
    //2.調(diào)整(iOS8以上)view邊距(或者在cell中設(shè)置preservesSuperviewLayoutMargins,二者等效)
    if ([self.tableView respondsToSelector:@selector(setLayoutMargins:)]) {
        self.tableView.layoutMargins = UIEdgeInsetsZero;
    }
}
  • 對cell的LayoutMargins屬性的設(shè)置
  • 補(bǔ)充:對cell的設(shè)置可以寫在cellForRowAtIndexPath里,也可以寫在willDisplayCell方法里
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
      UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID forIndexPath:indexPath];

   //2.調(diào)整(iOS8以上)tableView邊距(與上面第2步等效,二選一即可)
    if ([cell respondsToSelector:@selector(setPreservesSuperviewLayoutMargins:)]) {
        cell.preservesSuperviewLayoutMargins = NO;
    }
   //3.調(diào)整(iOS8以上)view邊距
    if ([cell respondsToSelector:@selector(setLayoutMargins:)]) {
        [cell setLayoutMargins:UIEdgeInsetsZero];
    }
    return cell;
}

三種方法優(yōu)缺點(diǎn)比較:

  • 方法1 中做法a比較好用,可以使用系統(tǒng)自帶的cell, 但是需要添加一個(gè)view,設(shè)置背景顏色和frame. 而做法b僅僅為了分隔線卻還必須再自定義cell, 重寫drawRect,又顯得麻煩;

  • 方法2比較取巧,但是也需要自定義cell,在某些情況下不允許改變tableView的背景色,使用場景有限;

  • 方法3不需要自定義cell,對系統(tǒng)(iOS7,iOS8以上)做個(gè)簡單判斷即可.可惜網(wǎng)上很多文章寫的不對,很多人不會正確使用,有些會用的人也說不清楚原理,只管復(fù)制粘貼.
    比如網(wǎng)上流傳的一般是這樣,需要四步,雖然真的管用,但多了一步[cell setSeparatorInset:UIEdgeInsetsZero];而且原理也沒講,估計(jì)是某大神寫的,根本不屑于過多解釋,讓我用起來很郁悶,網(wǎng)上流傳代碼:

首先在viewDidLoad方法中加上如下代碼:
-(void)viewDidLoad {
    [super viewDidLoad];
    if ([self.tableView respondsToSelector:@selector(setSeparatorInset:)]) {
    [self.tableView setSeparatorInset:UIEdgeInsetsZero];
    }
    if ([self.tableView respondsToSelector:@selector(setLayoutMargins:)]) {
    [self.tableView setLayoutMargins:UIEdgeInsetsZero];
}
然后在willDisplayCell方法中加入如下代碼:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if ([cell respondsToSelector:@selector(setSeparatorInset:)]) {
        [cell setSeparatorInset:UIEdgeInsetsZero];
   }
    if ([cell respondsToSelector:@selector(setLayoutMargins:)]) {
        [cell setLayoutMargins:UIEdgeInsetsZero];
    }
}

分割線不能全屏原理解析

  • 其實(shí)關(guān)于分隔線不能全屏的原理,蘋果官方在文件中已經(jīng)說明了,可以去看一下

  • 在iOS7之前系統(tǒng)默認(rèn)就是全屏的,iOS7時(shí)UITableView多了separatorInset屬性,可在UITableView的頭文件中查看,如下:

@property (nonatomic) UIEdgeInsets separatorInset NS_AVAILABLE_IOS(7_0) UI_APPEARANCE_SELECTOR; 
// allows customization of the frame of cell separators
  • iOS7時(shí)只要設(shè)置該屬性為UIEdgeInsetsZero就沒有問題了.

  • iOS8之后僅僅完成以上設(shè)置就不行了,仔細(xì)查看后發(fā)現(xiàn)iOS8的UIView
    的頭文件里又多了個(gè)layoutMargins屬性,并有官方注釋

@property (nonatomic) UIEdgeInsets layoutMargins NS_AVAILABLE_IOS(8_0);
/*
 -layoutMargins returns a set of insets from the edge of the view's bounds that denote a default spacing for laying out content.
 If preservesSuperviewLayoutMargins is YES, margins cascade down the view tree, adjusting for geometry offsets, so that setting the left value of layoutMargins on a superview will affect the left value of layoutMargins for subviews positioned close to the left edge of their superview's bounds
 If your view subclass uses layoutMargins in its layout or drawing, override -layoutMarginsDidChange in order to refresh your view if the margins change.
 */
大意是說:layoutMargins是view的bounds的邊距,用來調(diào)整內(nèi)容默認(rèn)邊距

如果preservesSuperviewLayoutMargins屬性是YES,那么設(shè)置父控件的layoutMargins邊距,
就會影響所有子控件的相對于父控件bounds的layoutMargins邊距

如果你的view的子類在布局或者繪圖中使用了layoutMargins屬性,需要重寫-layoutMarginsDidChange 方法,
以便當(dāng)邊距改變時(shí)能刷新你的view

正是因?yàn)閘ayoutMargins是UIView的新增屬性,tablet和cell作為UIView的子類都有這個(gè)屬性,所以相比較iOS7系統(tǒng),iOS8之后就多了兩步,必須同時(shí)再對tableView和cell的layoutMargins屬性進(jìn)行處理,才能讓分隔線真正全屏.

同時(shí)官方注釋中對preservesSuperviewLayoutMargins(意即:維持父控件的布局邊距)屬性的說明,也正好能說明網(wǎng)上另一種方法不設(shè)置self.tableView.layoutMargins = UIEdgeInsetsZero;而是設(shè)置cell.preservesSuperviewLayoutMargins = NO;為什么也能起作用

弄清楚了這些原理,就可以更好的記憶和使用這些方法,不用每次都去舊代碼查找或者去百度了.

說到了最后,不知道大家有沒有覺得影響分隔線全屏的元兇layoutMargins屬性 稍微有點(diǎn)眼熟呢?其實(shí)它在另一個(gè)地方也做了不少惡,就在storyboard中:

layoutMargins.png

PS:附效果圖如下:

設(shè)置之前效果圖:

1.png

設(shè)置完第1步self.tableView.separatorInset = UIEdgeInsetsZero;后效果圖:

2.png

設(shè)置完第2步self.tableView.layoutMargins = UIEdgeInsetsZero;后效果圖:

3.png

設(shè)置完第3步cell.layoutMargins = UIEdgeInsetsZero;后效果圖:

4.png

由于筆者水平有限,文中如果有錯(cuò)誤的地方,或者有更好的方法咙崎,還望大神指出胳喷。
附上本文的所有 demo 下載鏈接,【GitHub】席吴。
如果你看完后覺得對你有所幫助正驻,還望在 GitHub 上點(diǎn)個(gè) star。贈人玫瑰抢腐,手有余香姑曙。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市迈倍,隨后出現(xiàn)的幾起案子伤靠,更是在濱河造成了極大的恐慌,老刑警劉巖啼染,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件宴合,死亡現(xiàn)場離奇詭異,居然都是意外死亡迹鹅,警方通過查閱死者的電腦和手機(jī)卦洽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來斜棚,“玉大人阀蒂,你說我怎么就攤上這事〉苁矗” “怎么了蚤霞?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長义钉。 經(jīng)常有香客問我昧绣,道長,這世上最難降的妖魔是什么捶闸? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任夜畴,我火速辦了婚禮拖刃,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘贪绘。我一直安慰自己序调,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布兔簇。 她就那樣靜靜地躺著发绢,像睡著了一般。 火紅的嫁衣襯著肌膚如雪垄琐。 梳的紋絲不亂的頭發(fā)上边酒,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天,我揣著相機(jī)與錄音狸窘,去河邊找鬼墩朦。 笑死,一個(gè)胖子當(dāng)著我的面吹牛翻擒,可吹牛的內(nèi)容都是我干的氓涣。 我是一名探鬼主播,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼陋气,長吁一口氣:“原來是場噩夢啊……” “哼劳吠!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起巩趁,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤痒玩,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后议慰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蠢古,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年别凹,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了草讶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,773評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡炉菲,死狀恐怖堕战,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情颁督,我是刑警寧澤践啄,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站沉御,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏昭灵。R本人自食惡果不足惜吠裆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一伐谈、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧试疙,春花似錦诵棵、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至怀跛,卻和暖如春距贷,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背吻谋。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工忠蝗, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人漓拾。 一個(gè)月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓阁最,卻偏偏與公主長得像,于是被迫代替她去往敵國和親骇两。 傳聞我的和親對象是個(gè)殘疾皇子速种,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,689評論 2 354

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