将CALayer添加到UITableViewCell后滚动时消失

3

我想在我的UITableViewCell底部添加一个CALayer,以获得一些“阴影”效果。问题是当表格向上滚动并向屏幕上方滚动时,该图层会被移除,所以当您向下滚动时它不可见。如果将单元格向下滚动到屏幕外,然后再向上滚动,它们就会显示正常。

这里有一个gif展示了发生了什么。

这是我的做法:

- (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;
}

我也尝试使用每个单元格的唯一cellIdentifier,希望它们不会被重用,因此图层永远不会像这样被移除:
    //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...

当单元格被重用时,添加到其中的CALayer会被移除。为了让该层在单元格滚动离开和重新进入屏幕时保持存在,我需要做什么?
编辑:
我也尝试了这个方法,但它也不起作用:
- (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;
}
2个回答

4

千万不要为每个单元格使用不同的单元格标识符。这完全破坏了单元格重用机制,会导致内存使用不断增加,并强制你始终为每个索引创建新的单元格——这是最糟糕的情况。

每当一个单元格滚动到屏幕外时,它就会进入重用队列。然后,当一个新的索引路径滚动到视图中时,系统会从回收站中取出一个以前使用过的单元格并将其交给你。你应该假设它的结构已经完全形成(你添加的任何自定义字段都会在那里),但其中的内容全部都是错误的,需要完全设置。因此,如果你有一个带有3个标签的单元格,模型中的某些对象会将文本填充到1个标签、填充到2个标签或填充到所有3个标签中,则你应该始终对所有3个标签设置值,即使它是空字符串。这可以防止上次使用单元格时留下的值仍然存在。

这就像医生办公室为你准备填写的患者表格一样。你填写表格并将其交给职员。职员把信息键入计算机,然后把表格放回未填写的表格堆的顶部。下一个病人必须把表格上的每一项信息都清空,包括他们没有孩子、配偶、既往病史等等。否则上一个使用表格的人的信息将仍然存在于你的表格中。

至于阴影层,当你使用dequeueReusableCellWithIdentifier获取单元格时,只有在必须创建新单元格时才应该添加你的层。如果你得到了一个重用的单元格,该层已经存在,但你可能需要设置它的内容,如果它们从单元格到单元格发生变化。


感谢您抽出时间来回答。我完全理解UITableView如何重复使用单元格的工作原理。我所做的只是试图以某种方式修复问题,即使是错误的方式,只是为了让它正常工作。我已经更新了我的问题,并更清楚地定义了我所问的内容。 - random
除了您发布的代码有错之外,将图层添加到单元格的代码应该位于“if(!cell)”条件语句内部。相反,每次重用单元格时,都会向其添加一个新图层,这很糟糕。这告诉我您并没有像您认为的那样理解单元格重用。 - Duncan C
我想我应该把我尝试过的所有代码都发布出来。将其放在“if(!cell)”中也无法解决问题。 - random

3
事实证明,被移除的原因是添加了CALayer到单元格而不是UITableViewCell的contentView中。因此,正确的实现方式如下:
- (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;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接