如何使用Storyboard实现自定义表视图节页眉和页脚

Sea*_*mus 175 uitableview ios5 uistoryboard

在不使用故事板的情况下,我们可以简单地将其UIView拖到画布上,将其布局,然后将其设置在tableView:viewForHeaderInSectiontableView:viewForFooterInSection委托方法中.

我们如何使用StoryBoard完成此操作,我们无法将UIView拖到画布上

Tie*_*eme 382

只需使用原型单元格作为节标题和/或页脚.

  • 添加一个额外的单元格并将所需的元素放入其中.
  • 将标识符设置为特定的(在我的情况下为SectionHeader)
  • 实现tableView:viewForHeaderInSection:方法或tableView:viewForFooterInSection:方法
  • 使用[tableView dequeueReusableCellWithIdentifier:]来获得头
  • 实施tableView:heightForHeaderInSection:方法.

(见屏幕)

-(UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
    static NSString *CellIdentifier = @"SectionHeader"; 
    UITableViewCell *headerView = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (headerView == nil){
        [NSException raise:@"headerView == nil.." format:@"No cells with matching CellIdentifier loaded from your storyboard"];
    }
    return headerView;
}  
Run Code Online (Sandbox Code Playgroud)

编辑:如何更改标题标题(评论问题):

  1. 向标题单元格添加标签
  2. 将标签的标签设置为特定的数字(例如123)
  3. 在您的tableView:viewForHeaderInSection:方法中通过调用获取标签:
    UILabel *label = (UILabel *)[headerView viewWithTag:123]; 
Run Code Online (Sandbox Code Playgroud)
  1. 现在您可以使用标签设置新标题:
    [label setText:@"New Title"];
Run Code Online (Sandbox Code Playgroud)

  • 在iOS 6.0中,引入了`dequeueReusableHeaderFooterViewWithIdentifier`,现在比这个答案更受欢迎.但正确使用它现在需要更多步骤.我有指南@ http://samwize.com/2015/11/06/guide-to-customizing-uitableview-section-header-footer/. (13认同)
  • 晚到派对,但要禁用对截面标题视图的点击,只需在`viewForHeaderInSection`方法中返回cell.contentView(无需添加任何自定义UIViews). (7认同)
  • 请不要使用`UITableViewCell`作为标题视图.您将很难调试视觉故障 - 标题有时会因为单元格如何出列而消失,并且您将查找数小时为什么是这样,直到您意识到`UITableViewCell`不属于`UITableView`标题. (4认同)
  • @PaulVon我试着在我的最新项目中这样做,但是如果你这样做只是尝试在你的一个标题上长按它会崩溃 (3认同)
  • 不要使用UITableViewCells创建sectionHeaderViews,它会产生意外行为.请改用UIView. (3认同)
  • 这样做,如何更改标题标题? (2认同)
  • 我这样做了,但我有一个可能相关的问题.当我点击节标题时,它会选择它下面的表格单元格.这是不受欢迎的,因为我不想发生任何事情.我尝试将userInteractionEnabled设置为false但不起作用. (2认同)
  • 如果你使用`UITableViewCell`作为标题,当前的iOS 7有许多微妙的问题.值得注意的是,处理标题视图的委托方法(例如`-tableView:willDisplayHeaderView:forSection:`)永远不会触发,并且您无法使用` - [UITableView headerViewForSection:]`检索标题视图. (2认同)

Rob*_*Rob 90

我知道这个问题适用于iOS 5,但为了未来读者的利益,请注意我们现在可以使用的有效iOS 6 dequeueReusableHeaderFooterViewWithIdentifier代替dequeueReusableCellWithIdentifier.

所以viewDidLoad,请拨打registerNib:forHeaderFooterViewReuseIdentifier:registerClass:forHeaderFooterViewReuseIdentifier:.然后viewForHeaderInSection,打电话tableView:dequeueReusableHeaderFooterViewWithIdentifier:.您不使用此API的单元格原型(它是基于NIB的视图或以编程方式创建的视图),但这是用于出列页眉和页脚的新API.

  • *叹息*遗憾的是这两个关于使用NIB而不是原型细胞的清晰答案目前低于5票,并且"用原型细胞破解它"的答案高于200. (13认同)
  • 不同之处在于,使用Tieme的黑客,您可以在同一个故事板中进行设计,而不是使用单独的Xib (5认同)
  • 仅说它“旧”是不够的,恕我直言。接受的答案是一种笨拙的方法,可以绕过这样一个事实,即您不能拥有用于页眉和页脚视图的原型单元格。但我认为这完全是错误的,因为它假定页眉和页脚的出列与单元格的出列相同(对于页眉/页脚的较新 API 的存在表明可能并非如此)。接受的答案是一种创造性的解决方法,在 iOS 5 中是可以理解的,但是,在 iOS 6 及更高版本中,最好使用明确设计用于页眉/页脚重用的 API。 (2认同)

sam*_*ize 53

在iOS 6.0及更高版本中,新dequeueReusableHeaderFooterViewWithIdentifierAPI 已经发生了变化.

我已经写了一个指南(在iOS 9上测试过),可以这样总结:

  1. 子类 UITableViewHeaderFooterView
  2. 使用子类视图创建Nib,并添加1个容器视图,其中包含页眉/页脚中的所有其他视图
  3. 注册Nib viewDidLoad
  4. 实现viewForHeaderInSection并使用dequeueReusableHeaderFooterViewWithIdentifier以获取页眉/页脚

  • 谢谢你这个不是黑客的答案,以及正确的做事方式.另外,感谢您向我介绍UITableViewHeaderFooterVIew.顺便说一句,指南非常好!:) (2认同)
  • 这肯定是评分最高的答案! (2认同)

dam*_*mon 22

我在故事板中使用原型单元在iOS7中工作.我的自定义部分标题视图中有一个按钮,用于触发在故事板中设置的segue.

Tieme的解决方案开始

正如pedro.m指出的那样,问题在于点击节标题会导致选择节中的第一个单元格.

正如Paul Von指出的那样,通过返回单元格的contentView而不是整个单元格来解决这个问题.

然而,正如Hons所指出的那样,长按所述部分标题会使应用程序崩溃.

解决方案是从contentView中删除任何gestureRecognizers.

-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
     static NSString *CellIdentifier = @"SectionHeader";
     UITableViewCell *sectionHeaderView = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

     while (sectionHeaderView.contentView.gestureRecognizers.count) {
         [sectionHeaderView.contentView removeGestureRecognizer:[sectionHeaderView.contentView.gestureRecognizers objectAtIndex:0]];
     }

     return sectionHeaderView.contentView; }
Run Code Online (Sandbox Code Playgroud)

如果你没有在节标题视图中使用手势,这个小小的黑客似乎完成了它.

  • 你是对的.我刚测试了它和它的工作,所以我更新了我的帖子(http://hons82.blogspot.it/2014/05/uitableviewheader-done-right.html),其中包含我在研究期间找到的所有可能的解决方案.这个修复很多 (2认同)

小智 13

如果使用故事板,则可以使用tableview中的原型单元格来布局标题视图.设置一个唯一的id和viewForHeaderInSection,您可以使用该ID将单元格出列并将其强制转换为UIView.


JZ.*_*JZ. 12

如果你需要一个Swift实现,请按照接受的答案的说明,然后在你的UITableViewController中实现以下方法:

override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    return tableView.dequeueReusableCell(withIdentifier: "CustomHeader")
}

override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return 75
}
Run Code Online (Sandbox Code Playgroud)

  • 出于某种原因,它对我不起作用,直到我也覆盖了heightForHeaderInSection. (2认同)

Sea*_*mus 9

我提出的解决方案基本上与故事板引入之前使用的解决方案相同.

创建一个新的空接口类文件.根据需要将UIView拖到画布上.

手动加载nib,在viewForHeaderInSection或viewForFooterInSection委托方法中指定相应的页眉/页脚部分.

我希望Apple用故事板简化这个场景,并不断寻找更好或更简单的解决方案.例如,可以直接添加自定义表格页眉和页脚.

  • 这是真正的解决方案......不幸的是它并不是最重要的,所以我花了一段时间才发现它.我总结了我遇到的问题http://hons82.blogspot.it/2014/05/uitableviewheader-done-right.html (5认同)
  • 除了仅适用于原型单元,而不适用于静态单元. (2认同)

Vit*_*nko 5

当您返回单元格的contentView时,您将遇到两个问题:

  1. 与手势相关的崩溃
  2. 你不重用contentView(每次viewForHeaderInSection通话,你创建新的单元格)

解:

表头\页脚的包装类.它只是容器,继承自UITableViewHeaderFooterView,将细胞保持在里面

https://github.com/Magnat12/MGTableViewHeaderWrapperView.git

在UITableView中注册类(例如,在viewDidLoad中)

- (void)viewDidLoad {
    [super viewDidLoad];
    [self.tableView registerClass:[MGTableViewHeaderWrapperView class] forHeaderFooterViewReuseIdentifier:@"ProfileEditSectionHeader"];
}
Run Code Online (Sandbox Code Playgroud)

在你的UITableViewDelegate中:

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
    MGTableViewHeaderWrapperView *view = [tableView dequeueReusableHeaderFooterViewWithIdentifier:@"ProfileEditSectionHeader"];

    // init your custom cell
    ProfileEditSectionTitleTableCell *cell = (ProfileEditSectionTitleTableCell * ) view.cell;
    if (!cell) {
        cell = [tableView dequeueReusableCellWithIdentifier:@"ProfileEditSectionTitleTableCell"];
        view.cell = cell;
    }

    // Do something with your cell

    return view;
}
Run Code Online (Sandbox Code Playgroud)