UITableViewStylePlain和UITableViewStyleGrouped样式的区别及效果处理

创建UITableView 时, 需要设置TableView样式, 默认有两种样式:UITableViewStylePlain, UITableViewStyleGrouped

UITableView *tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height) style: UITableViewStyleGrouped]

下面先介绍下, 这两种样式以及区别:

一. UITableView样式介绍

UITableViewStylePlain 介绍

在tableView的UITableViewStylePlain中,当一个section的rows有一部分可见时,section的header和footer浮动在内容顶部。plain style的tableView可以有一个section索引,作为一个bar在table的右边(例如A ~ Z)。你可以点击一个特定的标签,跳转到目标section。
例如下图:

UITableViewStyleGroup 介绍

在tableView的UITableViewStyleGroup中,所有单元格拥有一个默认的背景颜色和默认背景视图。背景视图为特定section中的所有cell提供可视分组。例如,一个group可以是一个人的名字和标题,另一个group可以是电话,电子邮件帐户等。可参考iphone“设置”程序。
例如下图:

Group类型默认设置tableView灰色背景色,cell为白色背景色,section外边缘设置浅灰色边框,cell设置浅灰色间隔线。如下图:

二:区别总结:

UITableViewStylePlain使用

1.plain类型有多段时,滚动时Section Header 在顶部停留,有些界面比如设置界面,这些新特性将显得多余。(自带效果)

2.plain类型默认section之间没有中间的间距和头部间距(想让plain类型的section之间留有空白,需要在UITableView代理方法中return自定义的headerView和footerView,并在自定义的headerView 和 footerView 里面重写setFrame方法)

解决方案:让plain类型的UITableView的section头部视图不停留(取消粘性效果)
  • 方法一: 网上好多都是这个方法. 这个代码是通过scroll偏移量来监听和改变你的tableView的contentInset 可见很不好(试试就知道)
//去掉UItableview headerview黏性(sticky)
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    CGFloat sectionHeaderHeight = 30;
    if (scrollView.contentOffset.y <= sectionHeaderHeight&&scrollView.contentOffset.y>=0) {
        scrollView.contentInset = UIEdgeInsetsMake(-scrollView.contentOffset.y, 0, 0, 0);
    } else if (scrollView.contentOffset.y >= sectionHeaderHeight) {
        scrollView.contentInset = UIEdgeInsetsMake(-sectionHeaderHeight, 0, 0, 0);
    }
}
  • 方法二: 在自定义section的headerView中, 重写setFrame: 方法来重载table的section.
    • 注意:setFrame方法中需要拿到重载的table和section!
- (void)setFrame:(CGRect)frame {    
    CGRect sectionRect = [self.tableView rectForSection:self.section];
    CGRect newFrame = CGRectMake(CGRectGetMinX(frame), CGRectGetMinY(sectionRect), CGRectGetWidth(frame), CGRectGetHeight(frame)); 
    [super setFrame:newFrame];
}

UITableViewStyleGroup 使用

解决方案:去掉 UITableViewStyleGroup类型的多余间距
应用场景一: sction的头部视图和尾部视图,无任何内容
  • 此应用场景需要分两步做:
    第一步: 处理第一个section上边多余间距(2种方法)
  • 方法一: tableView的tableHeaderView属性
    • 注意: 设置tableView头部视图的高度为特小值,但不能为零,若为零的话,iOS会取默认值,就无法消除头部间距了。
- (void)viewDidLoad {
  //设置代理
    tableView.delegate = self;
  //隐藏UITableViewStyleGrouped上边多余的间隔
  tableView.tableHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, CGFLOAT_MIN)];
}
  • 方法二: 设置顶部额滚动区域
tableView.contentInset = UIEdgeInsetsMake(-20, 0, 0, 0);
  • 补充: 属性tableHeaderView和contentInset 结合使用, 可以设置表格第一个cell顶到最顶部
  tableView.tableHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, CGFLOAT_MIN)];
    tableView.contentInset = UIEdgeInsetsMake(-20, 0, 0, 0);

第二步: 处理每个section下边多余间距(2种方法)

  • Group样式, 默认每一组都会有头部和尾部间距, 这两个间距保留一个就可以了.另一个间距设置为0.

  • 方法一: tableView 属性sectionHeaderHeight 和 属性sectionFooterHeight , 处理多余间距

    //设置tableView主间距为20
    tableView.sectionHeaderHeight = 0;
    tableView.sectionFooterHeight = 20;
  • 方法二: 调用tableView的代理方法 , 设置尾部视图的高度,
    • 注意: 去掉的视图, 返回值不能为0,否则系统启用默认值。返回的高度使用极小值CGFLOAT_MIN。
    • 注意2: 调用下面两个tableView代理方法后, sectionHeaderHeight属性和sectionFooterHeight属性设置的值失效.
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
    return 44;
}
// 注意:return height 为 0,则 height 被设置成默认值
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{
    return CGFLOAT_MIN;
}
应用场景二: sction有头部标题 尾部标题

此应用场景两种方法取其一, 可以同时处理section顶部间距和中间间距

  • 方法一: 设置 tableView 属性sectionHeaderHeight 和 属性sectionFooterHeight , 可同时处理section多余顶部间距和中间间距
tableView.sectionHeaderHeight = 30;
tableView.sectionFooterHeight = 0;
  • 方法二:调用tableView的代理方法 , 设置头部视图和尾部视图的高度
//第二步:隐藏UITableViewStyleGrouped下边多余的间隔
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
    return 30;
}
// 注意:此时可以设置为0
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{
    return 0;
}
应用场景三: section自定义头部视图和尾部视图
  • 调用下面tableView代理方法 自定义头部视图和尾部视图后, 不需要做顶部间距处理, 第一个section头部视图会自动顶到最顶部.
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
}
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section{
}
  • 中间间距 只需要通过tableView代理方法, 调整头部视图或者尾部视图各自的高度即可.
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
    return 30;
}
//注意:此时可以设置为0
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{
    return 0;
}


三. 在 Storyboard 中 0 代码搞定顶部多余间距

没用 Storyboard 的同学使用上面的代码就 OK 了;
而在 Storyboard 中可以 0 代码搞定这个事:

首先,在第一个 Section 的上面拖进来一个空 UIView

然后选中这个 UIView 的 Runtime Attributes 栏,添加一个 frame 的 KeyPath

这样头部的间隔就乖乖的不见了:

刨根问底 UITableViewHeader 的猫腻

为什么刚才说 0.1 和 CGFLOAT_MIN 是等效的呢?经过研究,这个高度值的影响大概是这样的:

  1. 若传入的 height == 0,则 height 被设置成默认值
  2. 若 height 小于屏幕半像素对应的高度,这个 header 不在另一个像素渲染

半像素也就是 1.0 / scale / 2.0,如在 @2x 屏上是 0.25
直观的感受下,假如这个 height 被设置成 0.5 的样子:

导航栏下面的阴影线看上去宽了 0.5 像素的,Done。

由于笔者水平有限,文中如果有错误的地方,或者有更好的方法,还望大神指出。
附上本文的所有 demo 下载链接,【GitHub】
如果你看完后觉得对你有所帮助,还望在 GitHub 上点个 star。赠人玫瑰,手有余香。