Note that there are some explanatory texts on larger screens.

plurals
  1. POUsing cached UIView to set cell background view in tableView:willDisplayCell:forRowAtIndexPath:
    primarykey
    data
    text
    <p>This is my solution for setting custom grouped table view cell backgrounds:</p> <pre><code>- (UIView *)top { if (_top) { return _top; } _top = [[UIView alloc] init]; [_top setBackgroundColor:[UIColor blueColor]]; return _top; } // dot dot dot - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { NSInteger section = [indexPath section]; NSInteger row = [indexPath row]; NSInteger maxRow = [tableView numberOfRowsInSection:section] - 1; if (maxRow == 0) { [cell setBackgroundView:[self lonely]]; } else if (row == 0) { [cell setBackgroundView:[self top]]; } else if (row == maxRow) { [cell setBackgroundView:[self bottom]]; } else { [cell setBackgroundView:[self middle]]; } } </code></pre> <p>Obviously it doesn't work as expected which brings me here, but it does work when I <em>don't</em> use cached views:</p> <pre><code>UIView *background = [[UIView alloc] init]; if (maxRow == 0) { [background setBackgroundColor:[UIColor redColor]]; } else if (row == 0) { [background setBackgroundColor:[UIColor blueColor]]; } else if (row == maxRow) { [background setBackgroundColor:[UIColor yellowColor]]; } else { [background setBackgroundColor:[UIColor greenColor]]; } [cell setBackgroundView:background]; </code></pre> <hr> <p><em><strong>UPDATE:</em></strong> After Jonathan pointed out that I can't use the same view for more than one cell, I decided to follow the table view model where it has a queue of reusable cells. For my implementation, I have a queue of reusable background views (<code>_backgroundViewPool</code>):</p> <pre><code>@implementation RootViewController { NSMutableSet *_backgroundViewPool; } - (id)initWithStyle:(UITableViewStyle)style { if (self = [super initWithStyle:style]) { _backgroundViewPool = [[NSMutableSet alloc] init]; UITableView *tableView = [self tableView]; [tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"Cell"]; } return self; } #pragma mark - Table view data source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { // Return the number of sections. return 6; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { // Return the number of rows in the section. if (section == 0) { return 1; } return 10; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; [cell setSelectionStyle:UITableViewCellSelectionStyleNone]; [[cell textLabel] setText:[NSString stringWithFormat:@"[%d, %d]", [indexPath section], [indexPath row]]]; return cell; } #pragma mark - Table view delegate - (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { UIView *backgroundView = [cell backgroundView]; [_backgroundViewPool addObject:backgroundView]; } - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { NSInteger section = [indexPath section]; NSInteger row = [indexPath row]; NSInteger maxRow = [tableView numberOfRowsInSection:section] - 1; UIColor *color = nil; if (maxRow == 0) { // single cell color = [UIColor blueColor]; } else if (row == 0) { // top cell color = [UIColor redColor]; } else if (row == maxRow) { // bottom cell color = [UIColor greenColor]; } else { // middle cell color = [UIColor yellowColor]; } UIView *backgroundView = nil; for (UIView *bg in _backgroundViewPool) { if (color == [bg backgroundColor]) { backgroundView = bg; break; } } if (backgroundView) { [backgroundView retain]; [_backgroundViewPool removeObject:backgroundView]; } else { backgroundView = [[UIView alloc] init]; [backgroundView setBackgroundColor:color]; } [cell setBackgroundView:[backgroundView autorelease]]; } </code></pre> <p>It works except when you scroll really fast. Some of the background views disappear! I suspect the background views are still being used in more than one cell, but I really don't know what's going on because the background views are supposed to be removed from the queue once it's reused making it impossible for the background view to be used in more than one visible cell.</p> <hr> <p>I've been looking into this since I have posted this question. The current solutions for custom background views for grouped table view cells online are unsatisfactory, they don't used cached views. Additionally, I don't want to have use the solution proposed by XJones and jszumski because it's gonna get hairy once reusable custom cells (e.g., text field cell, switch cell, slider cell) are taken into account.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload