【问题标题】:Reusable TableView header views可重用的 TableView 标题视图
【发布时间】:2009-06-06 17:07:33
【问题描述】:

出于性能考虑,通常重用 UITableView 的单元格。 有没有办法对 TableView 标题的视图做同样的事情? 我说的是委托方法返回的那些:

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

我尝试执行以下操作,但似乎没有按预期工作:

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

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: CellIdentifier];
    if (cell == nil) {
        cell = [self getHeaderContentView: CellIdentifier];
    }
    return cell;
}

有没有办法重用标题的视图?

【问题讨论】:

  • 从 iOS 6 开始,您现在拥有 UITableViewHeaderFooterView,它使用了重用标识符。
  • 但目前您不能将 UITableViewHeaderFooterView 与 UI Builder 一起使用。

标签: iphone cocoa-touch


【解决方案1】:

Apple 内置重用 tableview 单元格的原因是因为虽然 tableview 可能有很多行,但只有少数几行显示在屏幕上。无需为每个单元分配内存,应用程序可以重用已经存在的单元并根据需要重新配置它们。

首先,标题视图只是 UIView,虽然 UITableViewCell 是 UIView 的子类,但它们并不打算作为节标题的视图。

此外,由于节标题通常比总行少得多,因此没有理由构建可重用性机制,事实上 Apple 还没有为通用 UIView 实现这一机制。

请注意,如果您只是为标题设置标签,则可以改用-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section

对于更自定义的东西,例如带有红色文本的标签(或按钮、图像等),您可以执行以下操作:

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
  UIView *headerView = [[[UIView alloc] initWithFrame:CGRectMake(0,0, 320, 44)] autorelease];
  UILabel *label = [[[UILabel alloc] initWithFrame:headerView.frame] autorelease];
  label.textColor = [UIColor redColor];
  label.text = [NSString stringWithFormat:@"Section %i", section];

  [headerView addSubview:label];
  return headerView;
}

【讨论】:

  • 我认为标签不应该是自动释放,而是在添加到 headerView 后释放。你有什么想法?
  • “几乎没有理由建立可重用性机制......” Martins 的评论通常是正确的,但并不完全正确。对于任何试图达到 60fps(如我)的人来说,带有自定义视图的 viewForHeaderInSection 是魔鬼。为每个标题启动一个新视图,特别是如果您的组不大,实际上将无法达到上述性能,因为它通常会花费我 5 FPS。如果您可以在设计中避免使用自定义标头,它将给您带来性能提升。
  • 但是如果您真的需要使用自定义标题视图,那么将 FPS 保持在 60 的最佳方法是什么?
  • 虽然你的解释很透彻,但这确实不能回答问题。
  • 从 iOS 6 开始我们也应该重用这些:UITableViewHeaderFooterView
【解决方案2】:

您可以通过创建 UITableViewHeaderFooterView 类来实现它 它是 UIView 的子类 您还需要创建一个单独的 XIB,因为它不会通过 UITableViewHeaderFooterView 创建自动创建。

用tableview注册Nib

[self.tblCart registerNib:[UINib nibWithNibName:@"CartHeaderView" bundle:nil] forHeaderFooterViewReuseIdentifier:@"CartHeader"];

现在您可以在 viewForHeaderInSection

中访问它
-(UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{

    CartHeaderView *sectionHeader=[tableView dequeueReusableHeaderFooterViewWithIdentifier:@"CartHeader"];
 return sectionHeader;
}

注意: 要设置背景颜色,您需要创建一个与节标题具有相同框架的子视图并为该视图设置颜色。

你可以关注

Changing the background color on a UITableViewHeaderFooterView loaded from a xib says to use contentView.backgroundColor instead

【讨论】:

    【解决方案3】:

    一个简单而有效的解决方案:

    @interface SectionedTableViewController ()
        @property (nonatomic, strong) UINib*          sectionHeaderNib;
        @property (nonatomic, strong) NSMutableArray* sectionHeaders;
    @end
    
    @implementation SectionedTableViewController
    
    @synthesize sectionHeaderNib = sectionHeaderNib_;
    @synthesize sectionHeaders = sectionHeaders_;
    
    - (void) viewDidUnload
    {
        self.sectionHeaders = nil;
        [super viewDidUnload];
    }
    
    - (NSMutableArray*) sectionHeaders
    {
        if (!sectionHeaders_)
            self.sectionHeaders = [NSMutableArray array];
        return sectionHeaders_;
    }
    
    
    - (UINib*) sectionHeaderNib
    {
        if (!sectionHeaderNib_)
            self.sectionHeaderNib = [UINib nibWithNibName: NSStringFromClass(YourHeaderView.class) bundle: nil];
        return sectionHeaderNib_;
    }
    
    
    - (YourHeaderView*) dequeueHeader
    {
        return [self.sectionHeaders firstObjectPassingTest: ^(id obj) { return (BOOL) ([obj superview] == nil); }];
    }
    
    
    - (NSString*) sectionHeaderTitleForSection: (NSInteger) section
    {
        return nil;
    }
    
    
    - (UIView*) tableView: (UITableView*) tableView viewForHeaderInSection: (NSInteger) section
    {
        YourHeaderView* headerView = [self dequeueHeader];
        if (!headerView)
        {
            headerView = [YourHeaderView instanceFromNib: self.sectionHeaderNib];
            [self.sectionHeaders addObject: headerView];
        }
        return headerView;
    }
    
    @end
    

    【讨论】:

    • 这是什么:firstObjectPassingTest?
    猜你喜欢
    • 1970-01-01
    • 2019-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-30
    • 1970-01-01
    • 2012-10-11
    相关资源
    最近更新 更多