滚动时重复 TableView 上的复选标记

Posted

技术标签:

【中文标题】滚动时重复 TableView 上的复选标记【英文标题】:Checkmark on TableView is repeating when scrolling 【发布时间】:2015-04-11 13:09:08 【问题描述】:

编辑: 添加了一个 else 语句以删除复选标记。但是,现在,它不再重复复选标记,但是如果标记了两个或多个单元格并且我向下滚动并向上滚动,它将删除除一个之外的所有单元格。任何想法为什么?当这种情况发生时,我很难理解细胞回收。

我一直在努力解决这个问题,因为我无法弄清楚。任何指针或帮助将不胜感激。

每次我选择一个单元格并滚动时,它都会随机重复复选标记。我正在通过使用包含 indexPath.row + 1 的数组检查 indexPath.row 来决定单元格是否需要复选标记。

滚动时更新标题和描述效果很好,只是选中标记起作用了。

这是我当前的 cellForRowAtIndexPath 代码:

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

    static NSString *simpleTableIdentifier = @"KnuterItem";
    if([s.taskArray valueForKey:@"TaskData"] != [NSNull null])
    
        KJBasicCell *cell = (KJBasicCell*)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];

        // Add utility buttons
        NSMutableArray *rightUtilityButtons = [NSMutableArray new];

        [rightUtilityButtons sw_addUtilityButtonWithColor:
         [UIColor colorWithRed:1.0f green:0.231f blue:0.188 alpha:1.0f]
                                                    title:@"Les mer"];

        cell.rightUtilityButtons = rightUtilityButtons;
        cell.delegate = self;

        if (cell == nil) 

            NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"KnuterItem" owner:self options:nil];
            cell = [nib objectAtIndex:0];
        

        NSDictionary    *item = [s.taskArray objectAtIndex:indexPath.row];

        if([item objectForKey:@"Title"] != [NSNull null])
            cell.titleLabel.text = [item objectForKey:@"Title"];
                if(s.textColor)
                    cell.titleLabel.textColor = s.textColor;

        if([item objectForKey:@"Description"] != [NSNull null])
            if (s.isNotAutoRowHeight == 0) 
                cell.descLabel.numberOfLines = 0;
             else 
                cell.descLabel.numberOfLines = 1;
            
            cell.descLabel.text = [item objectForKey:@"Description"];
                if(s.textColor)
                    cell.descLabel.textColor = s.textColor;
            cell.descriptionText = [item objectForKey:@"Description"];
        

        if([[s.selfArray valueForKey:@"CheckStat"] isEqualToString:@"(null)"])
        
            cell.accessoryType = UITableViewCellAccessoryNone;
        
        else if([[s.selfArray valueForKey:@"CheckStat"] length] == 0)
        
            if ([[item objectForKey:@"CheckStat"] containsString:@"1"])
                cell.accessoryType = UITableViewCellAccessoryCheckmark;
            else
                cell.accessoryType = UITableViewCellAccessoryNone;
        
        else
        
            NSLog(@"array: %@", [s.selfArray valueForKey:@"CheckStat"]);
            for(int i = 0; i < [[[s.selfArray valueForKey:@"CheckStat"] componentsSeparatedByString:@","] count]; i++)
            
                NSString    *checkedNumStr = [[[s.selfArray valueForKey:@"CheckStat"] componentsSeparatedByString:@","] objectAtIndex:i];
                if ([checkedNumStr intValue] == indexPath.row + 1)
                        cell.accessoryType = UITableViewCellAccessoryCheckmark;
                else
                    cell.accessoryType = UITableViewCellAccessoryNone;
            
        


        return cell;
    
    else
        return  nil;

didSelectRowAtIndex:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    if(cell.accessoryType == UITableViewCellAccessoryCheckmark)
    
        cell.accessoryType = UITableViewCellAccessoryNone;
    
    else
    
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
    
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    CheckStatStr = nil;
    for(int i = 0; i < [s.taskArray count]; i++)
    
        NSIndexPath *eachPath = [NSIndexPath indexPathForRow:i inSection:0] ;
        UITableViewCell *eachCell = [tableView cellForRowAtIndexPath:eachPath];
        if(eachCell.accessoryType == UITableViewCellAccessoryCheckmark)
        
            if([CheckStatStr length] == 0 || !CheckStatStr)
            
                CheckStatStr = [[NSMutableString alloc] init];
                [CheckStatStr setString:(NSString*)[NSString stringWithFormat:@"%d",i+1]];
            
            else
                [CheckStatStr appendString:[NSString stringWithFormat:@",%d",i+1]];
        
    
    if(CheckStatStr)
        s.OldCheckStatStr = [s.selfArray valueForKey:@"CheckStat"];
        [s.selfArray setValue:CheckStatStr forKey:@"CheckStat"];
    else
        [s.selfArray setValue:@"0" forKey:@"CheckStat"];
    

【问题讨论】:

你能分享一个你的数据源的例子吗? 数据源是一个用 json 填充的 NSMutableArray,因为我是从 mysql 数据库中查询它。数组存储信息如下:CheckStat = 1,5,8,9,15; ***.com/a/17540129/2099097 【参考方案1】:

勾选if ([checkedNumStr intValue] == indexPath.row + 1)并设置添加勾选标记,如果没有则需要设置cell.accessoryType = UITableViewCellAccessoryNone

if ([checkedNumStr intValue] == indexPath.row + 1)
    cell.accessoryType = UITableViewCellAccessoryCheckmark;
else
    cell.accessoryType = UITableViewCellAccessoryNone;

表格视图单元格会被重复使用,因此如果一个带有复选标记的单元格被重复用于您不希望有复选标记的行,则需要删除复选标记。

【讨论】:

@dan 您好,感谢您的回答,Dan。当我添加 else 语句以删除复选标记时,通过删除应该存在的复选标记向上滚动时它会搞砸。知道为什么会发生这种情况吗?【参考方案2】:

不看来源,我可以告诉你是细胞回收的受害者。 Apple 出于性能原因这样做,请确保您取消选中 tableView:cellForRowAtIndexPath: 中的单元格(如果不应该选中它)(删除复选标记),否则在回收另一个单元格时它将保留复选标记。cell.accessoryType = UITableViewCellAccessoryNone

用更多代码编辑:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    if(cell.accessoryType == UITableViewCellAccessoryCheckmark)
    
        cell.accessoryType = UITableViewCellAccessoryNone;
    
    else
    
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
    
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    s.taskArray[indexPath.row][@"CheckStat"] = @YES

【讨论】:

我现在有一个删除复选标记的语句,但是如果多个单元格有复选标记并且我向下滚动并向后滚动,它们都无法保留复选标记。知道为什么会发生这种情况吗? @Chue 您需要将复选标记保存到本地商店,因此请在-tableView:didSelectRowAtIndexPath: 中设置s.taskArray[indexPath.row][@"CheckStat"] = @YES :-) 这似乎没有帮助。也许这与我保存当前复选标记的方式有关。假设我在屏幕上有单元格 1 - 12,我检查了它们。它会正确保存复选标记,但如果我向下滚动并从单元格 6 - 18 中选择,当我尝试附加新的并且仅附加可见单元格时,1 - 6 将从我的 CheckStatStr 中删除。我在当前的 didSelectRowAtIndexPath 中进行了编辑。你知道我该如何处理吗? @Chue 用代码编辑。您应该为键 @"CheckStat" 保留一个 BOOL 的 NSValue 内部值,而不是使用 0 和 1(因为使用字符串作为布尔值的编程很糟糕)。您将需要重写 tableView:cellForRowAtIndexPath: 方法。【参考方案3】:

另一个原因是如果有任何图层支持的效果(即动画)...单击 CB 本身并弹出打开“查看效果检查器”..在那里您应该看到 CA 列表(核心动画)层..

如果您当时玩弄了 CB 的渲染,我建议您要么查看那里并启用正确的图层,要么重新连接渲染不良的渲染:D

【讨论】:

【参考方案4】:

使用 Swift 3.0,

cell.accessoryType = UITableViewCellAccessoryNone;

变成

`cell.accessoryType = UITableViewCellAccessoryType.none

【讨论】:

【参考方案5】:

我如何在 Swift 5

中解决这个问题

重复复选标记的主要原因是单元格可重复使用。然后显示单元格重用和复选标记 Still Apear 。我如何解决这个问题:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 

    let cell = self.schedulTable.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        as! scheduleCell

    cell.timeLable.text = self.timeArray[indexPath.row]
    // here is the code which clear checkmark on reuse
    if item.num >= 0 && item.isSelected == true
        if item.num == indexPath.row
            cell.accessoryType = .checkmark
        else
             cell.accessoryType = .none
        
    


       return cell
   



 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
 selected_Time = self.timeArray[indexPath.row]
    item.isSelected = true
   item.num = indexPath.row
    schedulTable.cellForRow(at: indexPath)?.accessoryType = .checkmark
  //schedulTable.reloadData()



func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) 
    schedulTable.cellForRow(at: indexPath)?.accessoryType = .none



struct Item 
 var num : Int
 var isSelected : Bool
init() 
    num = -1
    isSelected = false

【讨论】:

以上是关于滚动时重复 TableView 上的复选标记的主要内容,如果未能解决你的问题,请参考以下文章

TableView Cell 重用和不需要的复选标记 - 这让我很生气

当我向下滚动表格视图时,隐藏单元格的复选标记消失了

如何在单元格渲染后检查表格视图上的复选标记图标(附件视图)?

设置静态表格视图单元格的复选标记

使附件类型成为选定单元格的复选标记

tableview 编辑模式单元格选择复选标记在滚动时消失