ios 如何使用 UITableViewHeaderFooterView?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12900446/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 20:45:14  来源:igfitidea点击:

How to use UITableViewHeaderFooterView?

iosobjective-cuitableview

提问by Ashutosh

Hi I want to use UITableHeaderFooterViewin my app and i am doing this:

嗨,我想UITableHeaderFooterView在我的应用程序中使用,我正在这样做:

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    [_tableView registerClass:[M3CTableViewCell class] forCellReuseIdentifier:@"cell"];
    [_tableView registerClass:[M3CHeaderFooter class] forHeaderFooterViewReuseIdentifier:@"footer"];

}

- (UITableViewHeaderFooterView *)footerViewForSection:(NSInteger)section {
    M3CHeaderFooter * footer = [[M3CHeaderFooter alloc]initWithReuseIdentifier:@"footer"];
    footer.textLabel.text = @"Test";
    return footer;
}

By doing this I am not getting anything at Footer's place. And this method is not even getting called but I think this method is part of UITableViewDelegateprotocol.

通过这样做,我在页脚的地方没有得到任何东西。这个方法甚至没有被调用,但我认为这个方法是UITableViewDelegate协议的一部分。

回答by Raz

Using the new iOS 6 feature of reusable header/footer views involves two steps. You seem to be doing only the first step.

使用 iOS 6 的可重用页眉/页脚视图的新功能涉及两个步骤。你似乎只做了第一步。

First step: you're telling the table view what class to use for the section header view, by registering your custom subclass of UITableViewHeaderFooterView (I assume your M3CHeaderFooter is a subclass of UITableViewHeaderFooterView).

第一步:通过注册 UITableViewHeaderFooterView 的自定义子类(我假设您的 M3CHeaderFooter 是 UITableViewHeaderFooterView 的子类),您告诉表格视图将哪个类用于部分标题视图。

Second step: Tell the table view what view to use (AND reuse) for a header section by implementing the tableView delegate method

第二步:通过实现 tableView 委托方法告诉 table view 对 header 部分使用什么视图(和重用)

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section

So in your viewDidLoad you'd implement something like this:

因此,在您的 viewDidLoad 中,您将实现如下内容:

    // ****** Do Step One ******
    [_tableView registerClass:[M3CHeaderFooter class] forHeaderFooterViewReuseIdentifier:@"TableViewSectionHeaderViewIdentifier"];

Then you'd implement the table View delegate method in the class where you're creating and displaying your table view:

然后,您将在创建和显示表格视图的类中实现表格视图委托方法:

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    return 40.0;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    static NSString *headerReuseIdentifier = @"TableViewSectionHeaderViewIdentifier";

    // ****** Do Step Two *********
    M3CHeaderFooter *sectionHeaderView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:headerReuseIdentifier];
   // Display specific header title
   sectionHeaderView.textLabel.text = @"specific title";   

    return sectionHeaderView;    
}

Now mind you that you do not need to subclass UITableViewHeaderFooterView in order to use it. Before iOS 6, if you wanted to have a header view for a section, you'd implement the above tableView delegate method and tell the table view what view to use for each section. So each section had a different instance of a UIView which you provided. This means that if your tableView had 100 sections, and inside the delegate method you created a new instance of a UIView, then you would have given the tableView 100 UIViews for the 100 section headers that were displayed.

现在请注意,您不需要继承 UITableViewHeaderFooterView 来使用它。在 iOS 6 之前,如果你想要一个部分的标题视图,你需要实现上面的 tableView 委托方法并告诉表视图每个部分使用什么视图。所以每个部分都有一个你提供的 UIView 的不同实例。这意味着如果您的 tableView 有 100 个部分,并且在委托方法中您创建了一个 UIView 的新实例,那么您将为显示的 100 个部分标题提供 tableView 100 个 UIViews。

Using the new feature of reusable header/footer views, you create an instance of a UITableViewHeaderFooterView and the system reuses it for each displayed section header.

使用可重用页眉/页脚视图的新功能,您可以创建 UITableViewHeaderFooterView 的实例,系统会为每个显示的部分标题重用它。

If you wanted to have a reusable UITableViewHeaderFooterView without subclassing then you simply change your viewDidLoad to this:

如果你想拥有一个可重用的 UITableViewHeaderFooterView 而没有子类化,那么你只需将 viewDidLoad 更改为:

// Register the class for a header view reuse.
[_buttomTableView registerClass:[UITableViewHeaderFooterView class] forHeaderFooterViewReuseIdentifier:@"TableViewSectionHeaderViewIdentifier"];

and then your delegate method to this:

然后你的委托方法:

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    return 40.0;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    static NSString *headerReuseIdentifier = @"TableViewSectionHeaderViewIdentifier";

   // Reuse the instance that was created in viewDidLoad, or make a new one if not enough.
    UITableViewHeaderFooterView *sectionHeaderView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:headerReuseIdentifier];
    sectionHeaderView.textLabel.text = @"Non subclassed header";

    return sectionHeaderView;

}

I hope that was clear enough.

我希望这已经足够清楚了。

EDIT:When subclassing the header view, you can implement code similar to the following if you wish to add a custom view to the headerView:

编辑:当子类化 header 视图时,如果您希望向 headerView 添加自定义视图,则可以实现类似于以下的代码:

        // Add any optional custom views of your own
    UIView *customView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 50.0, 30.0)];
    [customView setBackgroundColor:[UIColor blueColor]];

    [sectionHeaderView.contentView addSubview:customView];

Doing this in the subclass, as opposed to viewForHeaderInSection: delegate method (as noted below by Matthias), will ensure that only one instance of any subviews are created. You can then add any properties within the subclass that will allow you to access your custom subview.

在子类中执行此操作,而不是 viewForHeaderInSection: 委托方法(如下面 Matthias 所述)将确保仅创建任何子视图的一个实例。然后,您可以在子类中添加任何允许您访问自定义子视图的属性。

回答by Cameron Lowell Palmer

UITableViewHeaderFooterView is one of the few places I would programmatically handle the view rather than use Storyboard or a XIB. Since you cannot officially use appearance proxy and there is no IB way to do it without abusing UITableViewCells. I do it the old-fashioned way and just use the tag on the label to fetch the custom elements.

UITableViewHeaderFooterView 是我以编程方式处理视图而不是使用 Storyboard 或 XIB 的少数几个地方之一。由于您不能正式使用外观代理,并且在不滥用 UITableViewCells 的情况下没有 IB 方法可以做到这一点。我用老式的方式来做,只使用标签上的标签来获取自定义元素。

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    UITableViewHeaderFooterView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:kSectionHeaderReuseIdentifier];
    if (headerView == nil) {
        [tableView registerClass:[UITableViewHeaderFooterView class] forHeaderFooterViewReuseIdentifier:kSectionHeaderReuseIdentifier];
        headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:kSectionHeaderReuseIdentifier];
    }

    UILabel *titleLabel = (UILabel *)[headerView.contentView viewWithTag:1];
    if (titleLabel == nil) {
        UIColor *backgroundColor = [UIColor blackColor];
        headerView.contentView.backgroundColor = backgroundColor;
        titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(10.0f, 0.0f, 300.0f, 44.0f)];
        titleLabel.textColor = [UIColor whiteColor];
        titleLabel.backgroundColor = backgroundColor;
        titleLabel.shadowOffset = CGSizeMake(0.0f, 0.0f);
        titleLabel.tag = 1;
        titleLabel.font = [UIFont systemFontOfSize:24.0f];
        [headerView.contentView addSubview:titleLabel];
    }

    NSString *sectionTitle = [self.sections objectAtIndex:section];
    if (sectionTitle == nil) {
        sectionTitle = @"Missing Title";
    }

    titleLabel.text = sectionTitle;

    return headerView;
}

回答by EricK

This is an old post and has good answers, but I wanted to share another work-around for a very similar issue I experienced.

这是一篇旧帖子,有很好的答案,但我想就我遇到的一个非常相似的问题分享另一个解决方法。

At first, I used:

起初,我使用了:

-(UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section

With a custom prototype cell for my header view. Subclassing UITableViewCell as such

为我的标题视图使用自定义原型单元格。子类化 UITableViewCell

    static NSString *cellIdentifier = @"CustomHeaderCell";
CustomHeaderCell * cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];

However, when animating TableView cells above section headers (making them twice as tall) the header view would disappear. This, as pointed out, is because the implementation only supplied a view, not a re-usable view.

但是,在部分标题上方为 TableView 单元格设置动画(使它们高两倍)时,标题视图将消失。正如所指出的,这是因为实现只提供了一个视图,而不是一个可重用的视图。

Instead of forgoing everything with the customized prototype cell, I implemented the UITableViewHeaderFooterWithIdentifier and set it as the prototyped cell's contentView, without subclassing UITableViewHeaderFooterWithIdentifier.

我没有放弃自定义原型单元格的所有内容,而是实现了 UITableViewHeaderFooterWithIdentifier 并将其设置为原型单元格的 contentView,而不是子类化 UITableViewHeaderFooterWithIdentifier。

  static NSString *customHeaderViewIdentifier = @"CustomHeaderView";
UITableViewHeaderFooterView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:customHeaderViewIdentifier];

headerView = (UITableViewHeaderFooterView *)cell.contentView;

I realize this creates two instances of the header view (at least I think it would..) however it does allow you to keep the benefits of a customized prototype cell without doing everything programatically.

我意识到这会创建标题视图的两个实例(至少我认为它会......)但是它确实允许您保留自定义原型单元的好处,而无需以编程方式完成所有操作。

Full code:

完整代码:

  // viewDidLoad
    [myTableView registerClass:[UITableViewHeaderFooterView class] forHeaderFooterViewReuseIdentifier:@"CustomHeaderView"];

// Implement your custom header
 -(UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
     static NSString *cellIdentifier = @"CustomHeaderCell";
    CustomHeaderCell * cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];

    static NSString *customHeaderViewIdentifier = @"CustomHeaderView";
    UITableViewHeaderFooterView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:customHeaderViewIdentifier];

// do your cell-specific code here
// eg. cell.myCustomLabel.text = @"my custom text"

    headerView = (UITableViewHeaderFooterView *)cell.contentView;

return headerView;
}

回答by Zorayr

There are a few ways of approaching this, but here is one a solution in Swift: the idea here is that we have a subclass of UITableViewHeaderFooterViewcalled SNStockPickerTableHeaderView; it exposes a method called, configureTextLabel()that when called, sets the font and the color of the text label. We call this method only after the title has been set, that is from, willDisplayHeaderView, and the font gets correctly set.

有几种方法可以解决这个问题,但这是Swift 中的一种解决方案:这里的想法是我们有一个子类UITableViewHeaderFooterViewcalled SNStockPickerTableHeaderView; 它公开了一个被调用的方法,configureTextLabel()当调用该方法时,设置文本标签的字体和颜色。我们仅在设置标题后调用此方法,即 from, willDisplayHeaderView,并且字体设置正确。

The header view also supports a custom line separator to set it apart from the rest of the cells.

标题视图还支持自定义行分隔符,以将其与其他单元格区分开来。

// MARK: UITableViewDelegate

func tableView(tableView:UITableView, willDisplayHeaderView view:UIView, forSection section:Int) {
  if let headerView:SNStockPickerTableHeaderView = view as? SNStockPickerTableHeaderView {
    headerView.configureTextLabel()
  }
}

func tableView(tableView:UITableView, viewForHeaderInSection section:Int) -> UIView? {
  var headerView:SNStockPickerTableHeaderView? = tableView.dequeueReusableHeaderFooterViewWithIdentifier(kSNStockPickerTableHeaderViewReuseIdentifier) as? SNStockPickerTableHeaderView
  if (headerView == nil) {
    // Here we get to customize the section, pass in background color, text 
    // color, line separator color, etc. 
    headerView = SNStockPickerTableHeaderView(backgroundColor:backgroundColor,
      textColor:primaryTextColor,
      lineSeparatorColor:primaryTextColor)
  }
  return headerView!
}

And here is the custom UITableViewHeaderFooterView:

这是自定义UITableViewHeaderFooterView

import Foundation
import UIKit

private let kSNStockPickerTableHeaderViewLineSeparatorHeight:CGFloat = 0.5
private let kSNStockPickerTableHeaderViewTitleFont = UIFont(name:"HelveticaNeue-Light", size:12)

let kSNStockPickerTableHeaderViewReuseIdentifier:String = "stock_picker_table_view_header_reuse_identifier"

class SNStockPickerTableHeaderView: UITableViewHeaderFooterView {

  private var lineSeparatorView:UIView?
  private var textColor:UIColor?

  required init(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }

  // We must implement this, since the designated init of the parent class
  // calls this by default!
  override init(frame:CGRect) {
    super.init(frame:frame)
  }

  init(backgroundColor:UIColor, textColor:UIColor, lineSeparatorColor:UIColor) {
    super.init(reuseIdentifier:kSNStockPickerTableHeaderViewReuseIdentifier)
    contentView.backgroundColor = backgroundColor
    self.textColor = textColor
    addLineSeparator(textColor)
  }

  // MARK: Layout

  override func layoutSubviews() {
    super.layoutSubviews()
    let lineSeparatorViewY = CGRectGetHeight(self.bounds) - kSNStockPickerTableHeaderViewLineSeparatorHeight
    lineSeparatorView!.frame = CGRectMake(0,
      lineSeparatorViewY,
      CGRectGetWidth(self.bounds),
      kSNStockPickerTableHeaderViewLineSeparatorHeight)
  }

  // MARK: Public API

  func configureTextLabel() {
    textLabel.textColor = textColor
    textLabel.font = kSNStockPickerTableHeaderViewTitleFont
  }

  // MARK: Private

  func addLineSeparator(lineSeparatorColor:UIColor) {
    lineSeparatorView = UIView(frame:CGRectZero)
    lineSeparatorView!.backgroundColor = lineSeparatorColor
    contentView.addSubview(lineSeparatorView!)
  }
}

Here is the result, see section header for, "Popular Stocks":

这是结果,请参阅“热门股票”部分标题:

                              enter image description here

                              在此处输入图片说明

回答by Bluezen

I can't comment under Cameron Lowell Palmer postbut to answer Christopher King, there is a simple way to ensure the re-use without sub-classing UITableViewHeaderFooterView and yet still using custom subviews.

我无法在Cameron Lowell Palmer 的帖子下发表评论,但为了回答 Christopher King,有一种简单的方法可以确保重用,无需对 UITableViewHeaderFooterView 进行子类化,但仍使用自定义子视图。

First, do NOT register the class for a header view reuse.

首先,不要为标题视图重用注册该类。

Then in tableView:viewForHeaderInSection: you simply have to create UITableViewHeaderFooterView when needed:

然后在 tableView:viewForHeaderInSection: 你只需要在需要时创建 UITableViewHeaderFooterView :

-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    static NSString *kYourTableViewReusableHeaderIdentifier = @"ID";

    UILabel *titleLabel = nil;

    UITableViewHeaderFooterView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:kYourTableViewReusableHeaderIdentifier];

    if (headerView == nil) {

        headerView = [[UITableViewHeaderFooterView alloc] initWithReuseIdentifier:kYourTableViewReusableHeaderIdentifier];

        titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(...)];
        titleLabel.tag = 1;
        // ... setup titleLabel 

        [headerView.contentView addSubview:titleLabel];
    } else {
        // headerView is REUSED
        titleLabel = (UILabel *)[headerView.contentView viewWithTag:1];
    }

    NSString *sectionTitle = (...); // Fetch value for current section
    if (sectionTitle == nil) {
        sectionTitle = @"Missing Title";
    }

    titleLabel.text = sectionTitle;

    return headerView;
}

回答by maz

Here is a "quick-and-dirty" way to get this going. It will make a small blue label in the header. I've confirmed that this renders OK in iOS 6 and iOS 7.

这是实现这一目标的“快速而肮脏”的方法。它将在标题中制作一个小的蓝色标签。我已经确认这在 iOS 6 和 iOS 7 中呈现正常。

in your UITableViewDelegate:

在你的 UITableViewDelegate 中:

 -(void)viewDidLoad
{
...
    [self.table registerClass:[UITableViewHeaderFooterView class] forHeaderFooterViewReuseIdentifier:@"Header"];
...
}

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

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    UITableViewHeaderFooterView *header = [tableView dequeueReusableHeaderFooterViewWithIdentifier:@"Header"];

    UILabel *leftlabel = [[UILabel alloc] initWithFrame:CGRectMake(0., 0., 400., 34.)];
    [leftlabel setBackgroundColor:[UIColor blueColor]];

    [header.contentView addSubview:leftlabel];
    return header;
}

回答by pkamb

In case it gets lost in the thorough answers above, the thing that people are likely missing (compared to the standard cellForRowAtIndexPath:method) is that you must register the class used for the section header.

万一它在上面的彻底答案中迷失了,人们可能缺少的东西(与标准cellForRowAtIndexPath:方法相比)是您必须注册用于节标题的类。

[tableView registerClass:[UITableViewHeaderFooterView class] forHeaderFooterViewReuseIdentifier:@"SectionHeader"];

Try adding registerClass:forHeaderFooterViewReuseIdentifier:and see if it starts working.

尝试添加registerClass:forHeaderFooterViewReuseIdentifier:,看看它是否开始工作。

回答by Mark A. Donohoe

One of the reasons that method may not be being called is the style of the table. Standard vs Grouped handles headers/footers differently. That may explain why it's not getting called.

可能不会调用方法的原因之一是表格的样式。标准与分组以不同方式处理页眉/页脚。这可以解释为什么它没有被调用。

回答by Nekto

  1. Set delegateproperty of UITableViewinstance to reference to the controller that implements next methods:

  2. Method that returns view of section footer:

    Asks the delegate for a view object to display in the footer of the specified section of the table view. - (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section

  3. Height of view in section footer:

    Asks the delegate for the height to use for the footer of a particular section.

    - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section

  1. 将实例的delegate属性设置UITableView为对实现下一个方法的控制器的引用:

  2. 返回节页脚视图的方法:

    要求委托在表视图的指定部分的页脚中显示一个视图对象。 - (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section

  3. 部分页脚中的视图高度:

    向代表询问用于特定部分页脚的高度。

    - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger) 部分