TableView 单元格重用和不需要的复选标记 - 这简直要了我的命

发布于 2024-11-14 21:09:10 字数 797 浏览 2 评论 0原文


Apple 的 iOS TableView 和单元格重用简直要了我的命。我搜索、搜索、研究,但找不到好的文档或好的答案。问题是,当 TableView 重用单元格时,在选定单元格上设置的复选标记(单元格附件)之类的内容会在表格视图中更下方的单元格中重复。我知道,由于内存限制,单元格重用是有意设计的,但是如果您有一个包含 50 个项目的列表,并且它开始在不需要的地方设置额外的复选标记,那么这会使整个努力变得毫无用处。

我想做的就是在我选择的单元格上设置复选标记。我已经尝试使用自己的自定义单元格类和由样板 TableView 类生成的标准单元格,但结果总是相同。

苹果甚至有一个名为 TouchCell 的示例项目,您可以从开发中心下载,该项目应该展示使用左侧带有图像控件的自定义单元设置复选标记的不同方式。该项目使用字典对象作为数据源,而不是可变数组,因此每个项目都有一个字符串值和布尔检查值。这个布尔检查值应该设置复选标记,以便它可以跟踪选定的项目。当您使用超过 15 个单元格填充 TableView 时,此示例项目也会显示这种愚蠢的行为。单元格的重用开始设置不需要的复选标记。

我什至尝试过为每个单元使用真正唯一的单元标识符。因此,我没有使用像@“Acell”这样的每个单元格,而是使用静态整型,转换为字符串,以便单元格得到@“cell1”,@“cell2”等。但在测试过程中,我可以看到数百个新单元格即使表格只有 30 个项目,也会在滚动期间生成。

它确实解决了复选标记重复问题,但我怀疑内存使用率太高了。

就好像当前不在表格可视区域中的单元格在滚动回到视图中时会重新创建一样。

有没有人想出一个优雅的解决方案来解决这种令人恼火的行为?

Apple's iOS TableView and cell reuse is killing me. I searched and searched and studied, but can't find good docs or good answers. The problem is that when the TableView reuses cells things like Checkmarks (cell accessory) set on a selected Cell are repeated in the cells further down in the table view. I understand that cell reuse is by design, due to memory constraints, but if you have a list with say 50 items, and it starts setting extra checkmarks where they're not wanted, this makes whole endeavor useless.

All I want to do is set a checkmark on a cell I've selected. I've tried this using my own custom cell class, and standard cells generated by a boiler plate TableView class, but it always ends up the same.

Apple even have an example project called TouchCell you can download from the dev center, that is supposed to show a different way of setting a checkmark using a custom cell with an image control on the left. The project uses a dictionary object for a data source instead of a muteable array, so for each item there is a string value and bool checked value. This bool checked value is supposed to set the checkmark so it can track selected items. This sample project also displays this goofy behavior as soon as you populate the TableView with 15+ cells. The reuse of cells starts setting unwanted check marks.

I've even tried experimenting with using a truely unique Cell Identifier for each cell. So instead of each cell having something like @"Acell" I used a static int, cast to a string so the cells got @"cell1", @"cell2" etc. During testing though, I could see that hundreds of new cells where generated during scrolling, even if the table only had 30 items.

It did fix the checkmark repeat problem, but I suspect the memory usage was going way too high.

It's as though the cells that are not currently in the viewable area of the table are created all over again when they are scrolled back into view.

Has anyone come up with an elegant solution to this irritating behavior?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

人疚 2024-11-21 21:09:10

单元格重用可能很棘手,但您必须记住两件事:

  • 对一种类型单元格使用一个标识符 - 仅当您使用不同的 UITableViewCell 时才需要使用多个标识符-一个表视图中的子类,您必须依赖它们对不同单元格的不同行为
  • 您重用的单元格可以处于任何状态,这意味着您必须再次配置单元格的各个方面 - 尤其是 checkmars /图像/文本/accessoryViews/ AccessoriesTypes 等

您需要做的是为您的复选标记状态创建一个存储 - 一个包含 bool 的简单数组(或分别包含 boolean NSNumber 对象的 NSArray)应该可以做到这一点。然后,当您必须创建/重用单元格时,请使用以下逻辑:

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *reuseIdentifier = @"MyCellType";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
    if(cell == nil) {
        /* create cell here */
    }
    // Configure cell now
    cell.textLabel.text = @"Cell text"; // load from datasource
    if([[stateArray objectAtIndex:indexPath.row] boolValue]) {
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
    } else {
        cell.accessoryType = UITableViewCellAccessoryNone;
    }
    return cell;
}

那么您将必须对点击做出反应:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [stateArray replaceObjectAtIndex:indexPath.row withObject:[NSNumber numberWithBool:![[stateArray objectAtIndex:indexPath.row] boolValue]]];
    [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}

只需记住为您的数据存储使用 NSMutableArray ;)

cell reusing can be tricky but you have to keep 2 things in mind:

  • Use one identifier for one type of cell - Using multiple identifiers is really only needed when you use different UITableViewCell-subclasses in one table view and you have to rely on their different behaviour for different cells
  • The cell you reuse can be in any state, which means you have to configure every aspect of the cell again - especially checkmars / images / text / accessoryViews / accessoryTypes and more

What you need to do is to create a storage for your checkmark states - a simple array containing bools (or NSArray containing boolean NSNumber objects respectively) should do it. Then when you have to create/reuse a cell use following logic:

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *reuseIdentifier = @"MyCellType";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
    if(cell == nil) {
        /* create cell here */
    }
    // Configure cell now
    cell.textLabel.text = @"Cell text"; // load from datasource
    if([[stateArray objectAtIndex:indexPath.row] boolValue]) {
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
    } else {
        cell.accessoryType = UITableViewCellAccessoryNone;
    }
    return cell;
}

then you will have to react on taps:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [stateArray replaceObjectAtIndex:indexPath.row withObject:[NSNumber numberWithBool:![[stateArray objectAtIndex:indexPath.row] boolValue]]];
    [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}

Just remember to use NSMutableArray for your data store ;)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文