Search code examples
iosobjective-cuitableviewcalayer

Adding CALayer to UITableViewCell removed after scroll


I am trying to add a CALayer to the bottom part of my UITableViewCell to get a bit of a "shadow" effect. The problem is when the table is scrolled up and off the screen the layer is removed, so when you scroll back down it isn't visible. If you scroll the cells downward off the screen then back up they appear fine.

I have a gif here showing what's happening.

This is how I'm doing it:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {


    static NSString *cellIdentifier = @"CellIdentifier";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];

    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
    }

    cell.textLabel.text = [NSString stringWithFormat:@"Row %d", (int)indexPath.row];

    CALayer *bottomBorder = [CALayer layer];
    bottomBorder.frame = CGRectMake(0.0f, cell.frame.size.height, cell.frame.size.width, 1.0f);
    bottomBorder.backgroundColor = [UIColor colorWithWhite:0.9f alpha:1.0f].CGColor;
    [cell.layer addSublayer:bottomBorder];

    cell.clipsToBounds = NO;

    cell.selectionStyle = UITableViewCellSelectionStyleNone;

    return cell;
}

Which I've also tried using a unique cellIdentifier for each cell in hopes that they wouldn't be reused and thus the layer never removed like this:

    //Same code as before just this changed
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:[NSString stringWithFormat:@"%ld_%ld", (long)indexPath.row, (long)indexPath.section]];

    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:[NSString stringWithFormat:@"%ld_%ld", (long)indexPath.row, (long)indexPath.section]];
    }

    //Same code continued...

So my problem is that when a cell is reused, the CALayer added to it is removed. What do I need to do to keep that layer there when the cell is scrolled off the screen and back on.

EDIT:

I've also tried this which doesn't work either:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {


    static NSString *cellIdentifier = @"CellIdentifier";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];

    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];

        CALayer *bottomBorder = [CALayer layer];
        bottomBorder.frame = CGRectMake(0.0f, cell.frame.size.height, cell.frame.size.width, 1.0f);
        bottomBorder.backgroundColor = [UIColor colorWithWhite:0.9f alpha:1.0f].CGColor;
        [cell.layer addSublayer:bottomBorder];

        cell.clipsToBounds = NO;
        cell.selectionStyle = UITableViewCellSelectionStyleNone;
    }

    cell.textLabel.text = [NSString stringWithFormat:@"Row %d", (int)indexPath.row];

    return cell;
}

Solution

  • It turns out the reason why it was being removed was because the CALayer was being added to the cell rather than to the UITableViewCell contentView. So the proper implementation is as follows:

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    
        static NSString *cellIdentifier = @"CellIdentifier";
    
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    
        if (!cell) {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
    
            CALayer *bottomBorder = [CALayer layer];
            bottomBorder.frame    = CGRectMake(0.0f,
                                               (CGRectGetHeight(cell.contentView.bounds) - 1),
                                               CGRectGetWidth(cell.contentView.bounds),
                                               1.0f);
    
            bottomBorder.backgroundColor = [UIColor colorWithWhite:0.9f alpha:1.0f].CGColor;
            [cell.contentView.layer addSublayer:bottomBorder];
        }
    
        cell.textLabel.text = [NSString stringWithFormat:@"Row %d", (int)indexPath.row];
    
        return cell;
    }