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

不使用故事板,我们可以简单地将UIView拖到canvas上,然后将其放置在tableView:viewForHeaderInSectiontableView:viewForFooterInSection委托方法中。

我们如何用StoryBoard来完成这个工作,我们不能将UIView拖到canvas上

只需使用原型单元格作为您的部分页眉和/或页脚。

  • 添加一个额外的单元格,并把你想要的元素在里面。
  • 设置标识符为特定的东西(在我的情况下,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; } 

编辑:如何更改标题标题(注释的问题):

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

我知道这个问题是针对iOS 5的,但为了未来读者的利益,请注意,我们现在可以使用dequeueReusableHeaderFooterViewWithIdentifier而不是dequeueReusableCellWithIdentifier

因此,在viewDidLoad ,调用registerNib:forHeaderFooterViewReuseIdentifier:registerClass:forHeaderFooterViewReuseIdentifier: 然后在viewForHeaderInSection ,调用tableView:dequeueReusableHeaderFooterViewWithIdentifier: viewForHeaderInSection 您不使用此API的单元格原型(它是基于NIB的视图或以编程方式创build的视图),但是这是用于出列页眉和页脚的新API。

在iOS 6.0和更高版本中,新的dequeueReusableHeaderFooterViewWithIdentifier API已经改变了。

我写了一个指南 (在iOS 9上testing),可以概括为:

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

我使用故事板中的原型单元在iOS7中工作。 我在自定义区域标题视图中有一个button,触发在故事板中设置的segue。

从铁梅的解决scheme开始

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

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

然而,正如Hons所指出的那样,长时间按下该部分标题将会使应用程序崩溃。

解决scheme是从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; } 

如果你在部分头部视图中没有使用手势,这个小小的破解似乎就完成了。

如果使用故事板,则可以使用tableview中的原型单元格来布局标题视图。 设置一个唯一的ID和viewForHeaderInSection你可以出队的单元格与该ID并将其投射到一个UIView。

我提出的解决scheme基本上是在介绍故事板之前使用的解决scheme。

创build一个新的空接口类文件。 将UIView拖到canvas上,根据需要布局。

手动加载笔尖,分配给viewForHeaderInSection或viewForFooterInSection委托方法中适当的页眉/页脚部分。

我希望苹果公司用故事板简化了这种情况,并不断寻找更好或更简单的解决scheme。 例如自定义表头和页脚是直接添加。

如果你需要一个Swift实现这个按照接受的答案的指示,然后在你的UITableViewController实现以下方法:

 override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { let cell = self.tableView.dequeueReusableCell(withIdentifier: "CustomHeader") as! CustomHeaderUITableViewCell return cell } override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { return 75 } 

当你返回单元格的contentView时,你会遇到2个问题:

  1. 与手势相关的崩溃
  2. 你不重复使用contentView(每次在viewForHeaderInSection调用,你创build新的单元格)

解:

表头\页脚的包装类。 它只是容器,从UITableViewHeaderFooterViewinheritance,里面持有单元格

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

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

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

在你的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; } 

我曾经做了以下事情懒洋洋地创build页眉/页脚视图:

  • 为节标题/页脚添加一个自由视图控制器到故事板
  • 在视图控制器中处理所有的东西
  • 在表视图控制器提供了一个可变的数组控制器的节/页眉join[NSNull null]
  • 在viewForHeaderInSection / viewForFooterInSection中,如果视图控制器还不存在,用storyboards创build它instantiateViewControllerWithIdentifier,记住它在数组中并返回视图控制器视图

你应该使用Tieme的解决scheme作为基础,但忘记了viewWithTag:和其他腥意,而是尝试重新加载您的标题(通过重新加载该部分)。

所以,当你坐在你的自定义单元格标题视图与所有漂亮的AutoLayout东西,只是出列它,并返回contentView设置后,如:

 -(UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { static NSString *CellIdentifier = @"SectionHeader"; SettingsTableViewCell *sectionHeaderCell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; sectionHeaderCell.myPrettyLabel.text = @"Greetings"; sectionHeaderCell.contentView.backgroundColor = [UIColor whiteColor]; // don't leave this transparent return sectionHeaderCell.contentView; } 

跟进达蒙的build议 ,这里是我如何使标题可以select像一个正常的行与披露指标。

我从UIButton(子类名称“ButtonWithArgument”)中添加了一个Button子类,并将其删除了标题文本(粗体“Title”文本是原型单元格中的另一个UILabel)

界面生成器中的按钮

然后将Button设置为整个标题视图,并添加了Avario的技巧的披露指标

 - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { static NSString *CellIdentifier = @"PersonGroupHeader"; UITableViewCell *headerView = (UITableViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if(headerView == nil) { [NSException raise:@"headerView == nil, PersonGroupTableViewController" format:[NSString stringWithFormat:@"Storyboard does not have prototype cell with identifier %@",CellIdentifier]]; } // https://stackoverflow.com/a/24044628/3075839 while(headerView.contentView.gestureRecognizers.count) { [headerView.contentView removeGestureRecognizer:[headerView.contentView.gestureRecognizers objectAtIndex:0]]; } ButtonWithArgument *button = (ButtonWithArgument *)[headerView viewWithTag:4]; button.frame = headerView.bounds; // set tap area to entire header view button.argument = [[NSNumber alloc] initWithInteger:section]; // from ButtonWithArguments subclass [button addTarget:self action:@selector(headerViewTap:) forControlEvents:UIControlEventTouchUpInside]; // https://stackoverflow.com/a/20821178/3075839 UITableViewCell *disclosure = [[UITableViewCell alloc] init]; disclosure.accessoryType = UITableViewCellAccessoryDisclosureIndicator; disclosure.userInteractionEnabled = NO; disclosure.frame = CGRectMake(button.bounds.origin.x + button.bounds.size.width - 20 - 5, // disclosure 20 px wide, right margin 5 px (button.bounds.size.height - 20) / 2, 20, 20); [button addSubview:disclosure]; // configure header title text return headerView.contentView; } - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { return 35.0f; } -(void) headerViewTap:(UIGestureRecognizer *)gestureRecognizer; { NSLog(@"header tap"); NSInteger section = ((NSNumber *)sender.argument).integerValue; // do something here } 

ButtonWithArgument.h

 #import <UIKit/UIKit.h> @interface ButtonWithArgument : UIButton @property (nonatomic, strong) NSObject *argument; @end 

ButtonWithArgument.m

 #import "ButtonWithArgument.h" @implementation ButtonWithArgument @end 

这里是@Vitaliy Gozhenko的答案 ,在Swift中。
总结一下,你将创build一个包含UITableViewCell的UITableViewHeaderFooterView。 这个UITableViewCell将是“美丽的”,您可以在故事板中进行devise。

  1. 创build一个UITableViewHeaderFooterView类

     class CustomHeaderFooterView: UITableViewHeaderFooterView { var cell : UITableViewCell? { willSet { cell?.removeFromSuperview() } didSet { if let cell = cell { cell.frame = self.bounds cell.autoresizingMask = [UIViewAutoresizing.FlexibleHeight, UIViewAutoresizing.FlexibleWidth] self.contentView.backgroundColor = UIColor .clearColor() self.contentView .addSubview(cell) } } } 
  2. 在你的viewDidLoad函数中将你的tableview与这个类相关联:

     self.tableView.registerClass(CustomHeaderFooterView.self, forHeaderFooterViewReuseIdentifier: "SECTION_ID") 
  3. 当询问段落标题时,将一个CustomHeaderFooterView出队,并向其中插入一个单元格

     func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { let view = self.tableView.dequeueReusableHeaderFooterViewWithIdentifier("SECTION_ID") as! CustomHeaderFooterView if view.cell == nil { let cell = self.tableView.dequeueReusableCellWithIdentifier("Cell") view.cell = cell; } // Fill the cell with data here return view; } 

我在一个情况下遇到了麻烦,在这个情况下,即使采取了所有适当的步骤,标题也从未被重用过。

所以作为一个提示,大家想要达到显示空白部分(0行)的情况应该警告:

dequeueReusableHeaderFooterViewWithIdentifier将不会重用该标题,直到您至less返回一行

希望它有帮助

怎么样解决scheme的标题是基于视图数组:

 class myViewController: UIViewController { var header: [UILabel] = myStringArray.map { (thisTitle: String) -> UILabel in let headerView = UILabel() headerView.text = thisTitle return(headerView) } 

接下来在代表:

 extension myViewController: UITableViewDelegate { func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { return(header[section]) } } 
  1. StoryBoard添加单元格,并设置reuseidentified

    SB

  2.  class TP_TaskViewTableViewSectionHeader: UITableViewCell{ } 

    链接

  3. 使用:

     func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { let header = tableView.dequeueReusableCell(withIdentifier: "header", for: IndexPath.init(row: 0, section: section)) return header }