TableView 单元格重用导致按钮标题在滚动时更改

Posted

技术标签:

【中文标题】TableView 单元格重用导致按钮标题在滚动时更改【英文标题】:TableView cell reuse causing the button title to change while scrolling 【发布时间】:2015-06-22 05:39:39 【问题描述】:

我有一个显示名称和标题为“关注”按钮的列表。当我点击按钮标题应更改为“取消关注”。如果我再次点击按钮,标题应再次更改为“关注”。这工作正常,但是当我滚动表格时,其他单元格的标题也会由于单元格重用而发生变化。

代码如下:

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

    static NSString *CellIdentifier = @"AuthorsListCell";
    AuthorsListTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier
                                                                     forIndexPath:indexPath];
    dic_eachAuthor = [[_arr_authors objectAtIndex:indexPath.row] mutableCopy];

    cell.lbl_authorName.text = [dic_eachAuthor objectForKey:@"name"];
    cell.btn_followOrUnfollow.tag = indexPath.row;

    if([dic_eachAuthor valueForKey:@"follow"])
        [cell.btn_followOrUnfollow setTitle:@"UnFollow" forState:UIControlStateNormal];
    
    else

        [cell.btn_followOrUnfollow setTitle:@"Follow" forState:UIControlStateNormal];
    

    // action button method declarations
    [cell.btn_followOrUnfollow addTarget:self action:@selector(followOrUnfollow:) forControlEvents:UIControlEventTouchUpInside];
    cell.selectionStyle = UITableViewCellSelectionStyleNone;

    return cell;



    -(void)followOrUnfollow:(UIButton *)sender

    if ([sender.titleLabel.text isEqualToString:@"Follow"]) 
        [sender setTitle:@"UnFollow" forState:UIControlStateNormal];
        [dic_eachAuthor setValue:@"1" forKey:@"follow"];

    
    else if ([sender.titleLabel.text isEqualToString:@"UnFollow"]) 
        [sender setTitle:@"Follow" forState:UIControlStateNormal];
        [dic_eachAuthor setValue:nil forKey:@"follow"];


    



请提出一些防止单元重复使用的建议。

【问题讨论】:

为“如果单元格为 nil”添加代码,因为每次初始化新单元格时。所以你正面临这个问题。 cell = (ListTableViewCell *)[[ListTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier: CellIdentifier]; 不,它不能解决问题。 【参考方案1】:

在 cellForRowAtIndexPath 的 followOrUnfollow 中也添加此条件

if ([sender.titleLabel.text isEqualToString:@"Follow"]) 
        [sender setTitle:@"UnFollow" forState:UIControlStateNormal];

    
    else if ([sender.titleLabel.text isEqualToString:@"UnFollow"]) 
        [sender setTitle:@"Follow" forState:UIControlStateNormal];


    

【讨论】:

【参考方案2】:

在数据源中存储关注/取消关注状态信息。

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

    static NSString *CellIdentifier = @"CellIdentifier";
    ListTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier
                                                                     forIndexPath:indexPath];

    cell.lbl_authorName.text = [[_arr_authors objectAtIndex:indexPath.row] objectForKey:@"name"];
    cell.btn_followOrUnfollow.tag = indexPath.row;

    // action button method declarations
    [cell.btn_followOrUnfollow addTarget:self action:@selector(followOrUnfollow:) forControlEvents:UIControlEventTouchUpInside];

    NSString *btnTitle = [[_arr_authors objectAtIndex:indexPath.row] objectForKey:@"userFollowUnfollow"];
     [sender setTitle:btnTitle forState:UIControlStateNormal];

    cell.selectionStyle = UITableViewCellSelectionStyleNone;

    return cell;


-(void)followOrUnfollow:(UIButton *)sender

    if ([sender.titleLabel.text isEqualToString:@"Follow"]) 
        [sender setTitle:@"UnFollow" forState:UIControlStateNormal];

    
    else if ([sender.titleLabel.text isEqualToString:@"UnFollow"]) 
        [sender setTitle:@"Follow" forState:UIControlStateNormal];
    

    [[_arr_authors objectAtIndex:sender.tag]  setValue:sender.titleLabel.text forKey:@"userFollowUnfollow"];


【讨论】:

添加这些行会导致按钮标题显示为空白,当我点击按钮时应用程序崩溃。【参考方案3】:

当您最初填充表格行时,您从此处的数组cell.lbl_authorName.text = [[_arr_authors objectAtIndex:indexPath.row] objectForKey:@"name"]; 执行此操作。问题是您没有从该数组中填充关注或取消关注信息。所以你所做的只是切换一个按钮,并且没有保存该按钮的状态。您需要做的是修改数组以有一个地方来保存关注/取消关注状态。然后从此数组中填充表格单元格中的状态。那么当你调用followOrUnfollow:时你需要修改数组中的状态。

当单元格被重用时,它会检查原始数组以填充它,从数组中填充后续元素,然后您将被设置。

编辑添加了一些代码:

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

    static NSString *CellIdentifier = @"CellIdentifier";
    ListTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier                                                                     forIndexPath:indexPath];

    cell.lbl_authorName.text = [[_arr_authors objectAtIndex:indexPath.row] objectForKey:@"name"];
    cell.btn_followOrUnfollow.tag = indexPath.row;
    if([[_arr_authors objectAtIndex:indexPath.row] valueForKey:@"follow"])
          [cell.btn_followOrUnfollow setTitle:@"UnFollow" forState:UIControlStateNormal];
    else
         [cell.btn_followOrUnfollow setTitle:@"Follow" forState:UIControlStateNormal];
    

    // action button method declarations
    [cell.btn_followOrUnfollow addTarget:self action:@selector(followOrUnfollow:) forControlEvents:UIControlEventTouchUpInside];
    cell.selectionStyle = UITableViewCellSelectionStyleNone;

    return cell;


-(void)followOrUnfollow:(UIButton *)sender

    if ([sender.titleLabel.text isEqualToString:@"Follow"]) 
        [sender setTitle:@"UnFollow" forState:UIControlStateNormal];
        [[_arr_authors objectAtIndex:sender.tag] setValue:1 forKey:@"follow"]
    
    else if ([sender.titleLabel.text isEqualToString:@"UnFollow"]) 
        [sender setTitle:@"Follow" forState:UIControlStateNormal];
        [[_arr_authors objectAtIndex:sender.tag] setValue:0 forKey:@"follow"]
    

我不在我的普通机器上,所以语法可能不正确,但你应该明白了。另请注意,您必须将 follow 属性添加到 _arr_authors

【讨论】:

你能告诉我如何用一些代码来做。感谢您的建议。 例如添加了代码示例,语法可能不正确但概念在那里,祝你好运! 字典中follow key的初始值应该是多少? 无论您的默认值是什么,我的猜测是您的默认值没有遵循,所以它会是 0。 请查看问题中已编辑的代码,它仍然无法正常工作。每当我滚动回顶部时,即使在它们被点击之后,标题也会再次变为“关注”。然而,底部单元格现在没有更改数据。跟随键的默认值也是 nil【参考方案4】:

你在这里遗漏了一些东西,试试这个:

-(void)followOrUnfollow:(UIButton *)sender

    NSDictionary *dict = (NSDictionary *) _arr_authors[sender tag];
    if ([[dict objectForKey:@"name"] isEqualToString:@"Follow"]) 
     
        [sender setTitle:@"UnFollow" forState:UIControlStateNormal];

     
     else if ([[dict objectForKey:@"name"] isEqualToString:@"UnFollow"]) 
    
        [sender setTitle:@"Follow" forState:UIControlStateNormal];
    

【讨论】:

【参考方案5】:

你是重复使用的单元格,所以请在 AuthorsListTableViewCell 中实现这个方法:

-(void) prepareForReuse
  [super prepareForReuse];
  [self.btn_followOrUnfollow setTitle:@"Follow" forState:UIControlStateNormal];

// 如果单元格是可重用的(具有重用标识符),则在从表格视图方法 dequeueReusableCellWithIdentifier: 返回单元格之前调用它。如果你覆盖,你必须调用 super。 并为单元格设置正确的默认值。

我也推荐这样实现:

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

    static NSString *CellIdentifier = @"AuthorsListCell";
    AuthorsListTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier
                                                                     forIndexPath:indexPath];

    cell.lbl_authorName.text = [dic_eachAuthor objectForKey:@"name"];
    cell.btn_followOrUnfollow.tag = indexPath.row;

    [cell.btn_followOrUnfollow setTitle:@"Follow forState:UIControlStateNormal];
    [cell.btn_followOrUnfollow setTitle:@"UnFollow" forState:UIControlStateSelected];

    if([dic_eachAuthor valueForKey:@"follow"])
        cell.btn_followOrUnfollow.selected = YES;
     else
        cell.btn_followorUnfollow.selected = NO;
    
    // action button method declarations
    [cell.btn_followOrUnfollow addTarget:self action:@selector(followOrUnfollow:) forControlEvents:UIControlEventTouchUpInside];
    cell.selectionStyle = UITableViewCellSelectionStyleNone;

    return cell;



    -(void)followOrUnfollow:(UIButton *)sender

    sender.selected = !sender.selected;

    if ([sender.titleLabel.text isEqualToString:@"Follow"]) 
        [dic_eachAuthor setValue:@"1" forKey:@"follow"];
    
    else if ([sender.titleLabel.text isEqualToString:@"UnFollow"]) 
        [dic_eachAuthor setValue:nil forKey:@"follow"];
    



在 AuthorsListTableViewCell 中

-(void) prepareForReuse
  [super prepareForReuse];
  self.btn_followOrUnfollow.selected = NO;

【讨论】:

以上是关于TableView 单元格重用导致按钮标题在滚动时更改的主要内容,如果未能解决你的问题,请参考以下文章

向下滚动时不会出现 Swift Expandable tableView 单元格按钮

禁用单元重用的开销

带有两个自定义单元格的 TableView 导致单元格重用问题(Swift 4)

重用 tableview 单元格中的元素

由于可重用性问题,tableview 单元格上的图像重复

滚动时在最后一个 tableView 单元中添加按钮显示两次