IOS:在uitableviewcell中保持按钮状态

Posted

技术标签:

【中文标题】IOS:在uitableviewcell中保持按钮状态【英文标题】:IOS: Maintaining button state in uitableviewcell 【发布时间】:2012-02-23 23:31:41 【问题描述】:

我有一个 iPhone 应用程序问题困扰了我好几天,而且看起来真的不应该这么难,所以我确定我遗漏了一些明显的东西。我研究了很多关于“类似”主题的论坛讨论,但没有任何具体解决这个问题。

为了清楚起见,如果我应该研究一些文档或其他来源,请指出正确的方向。

来了……

我有一个在表格 (uitableview) 中显示给用户的项目列表。每个项目的单元格 (uitableviewcell) 是自定义的,包含一个图像和一个赞按钮 (uibutton)。正如预期的那样,对于表中的每个项目,用户都可以单击 Like 按钮或忽略它。点赞按钮调用一个单独的进程来更新服务器。很简单吧?

那么,问题来了:

当在特定单元格上单击 Like 按钮时,Selected 状态工作正常,但当您将单元格滚动到视图之外时,表格中的其他随机单元格将 Like 按钮显示为 Selected,即使它们从未被触摸过。由于单元被重复使用,出于明显的性能原因,我理解为什么会发生这种情况。我不明白为什么我的方法(见下面的代码)不会像我认为的那样覆盖或重置按钮的状态。为简洁起见,我只在此处包含相关代码(希望格式正确):

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

    static NSString *CellIdentifier = @"MyCustomCell";
    MyCustomViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

if (cell == nil) 
    cell = [[MyCustomViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
    cell.selectionStyle = UITableViewCellSelectionStyleNone;


    NSString *myRating = [[self.dataArray objectAtIndex:indexPath.row] valueForKey:@"my_rating"];

    // Create the Like button
    UIButton *likeButton = [[UIButton alloc] initWithFrame:CGRectMake(260, 68, 40, 40)];
    [likeButton setImage:[UIImage imageNamed:@"thumbsUp"] forState:UIControlStateNormal];
    [likeButton setImage:[UIImage imageNamed:@"thumbsUpSelected"] forState:UIControlStateSelected];
    if (myRating == @"9") 
        [likeButton setSelected:YES];
    
    [likeButton setTitle:@"9" forState:UIControlStateNormal];
    [likeButton setTag:indexPath.row];
    [cell.contentView addSubview:likeButton];
    [likeButton addTarget:self action:@selector(likeButtonPressed:) forControlEvents:UIControlEventTouchUpInside];

    return cell;


- (void)likeButtonPressed:(UIButton *)sender 

    // Changed the Selected state on the button
    UIButton *button = (UIButton *)sender;
    button.selected = !button.selected;

    // Create a new object with the user's rating and then replace it in the dataArray
    NSString *ratingText = sender.titleLabel.text;    
    NSMutableArray *myMutableArray = [[self.dataArray objectAtIndex:row] mutableCopy];
    [myMutableArray setValue:ratingText forKey:@"my_rating"];
    [self.dataArray replaceObjectAtIndex:row withObject:myMutableArray];

所以,我已经经历了很多次迭代,但我似乎无法获得按钮的状态来显示那些被喜欢的项目的选定图像并为那些没有被喜欢的项目保留正常图像喜欢。

任何帮助或建议将不胜感激。

【问题讨论】:

我也有同样的问题。我在 tableView 的 HeaderSection 中有一个单选按钮。当我在 headerSection 中选择一个按钮时,会在 tableView 中选择随机单选按钮。你解决了你的问题。你能帮我么。?我必须在 tableView 中选择单个 radioButton。 【参考方案1】:

有一个简单的方法可以解决这个问题。您可以欺骗按钮以保持最新的选定状态。

制作一个可变数组,目的是保持按钮的选中状态

selectedButton = [[NSMutableArray alloc]init];//i've already defined the array at the .h file

for (int i = 0; i<yourTableSize; i++) //yourTableSize = how many rows u got

    [selectedButton addObject:@"NO"];

在 tableviewcell 方法中,声明你的按钮并设置它,以便它引用 mutablearray 来设置它的选定状态

static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil) 
 
    cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];


UIImage *img = [UIImage imageNamed:@"btn_unselected.png"];
UIButton *toggleButton = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, img.size.width, img.size.height)];
[toggleButton setImage:img forState:UIControlStateNormal];
img = [UIImage imageNamed:@"btn_selected.png"];
[toggleButton setImage:img forState:UIControlStateSelected];
[toggleButton setTag:indexPath.row+100];//set the tag whichever way you wanted it, i set it this way so that the button will have tags that is corresponding with the table's indexpath.row
[toggleButton addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:toggleButton];

//and now we set the button's selected state, everytime the table reuse/redraw the cell the button will set it's selected state according to the array

if([[selectedButton objectAtIndex:indexPath.row]isEqualToString:@"NO"])

    [toggleButton setSelected:NO];

else 

    [toggleButton setSelected:YES];


return cell;

最后,创建按钮被按下时触发的方法,以改变它的选中状态

-(void)buttonPressed:(UIButton*)sender

    int x = sender.tag - 100; //get the table's row
    if([sender isSelected]) //if the button is selected, deselect it, and then replace the "YES" in the array with "NO"
    
        [selectedButton replaceObjectAtIndex:x withObject:@"NO"];
        [sender setSelected:NO];
    
    else if (![sender isSelected]) //if the button is unselected, select it, and then replace the "NO" in the array with "YES"
    
        [selectedButton replaceObjectAtIndex:x withObject:@"YES"];
        [sender setSelected:YES];
    

【讨论】:

【参考方案2】:

问题在于,每次您创建或重复使用一个单元格时,您都会给它一个新的点赞按钮,所以当您重复使用一个点赞按钮已激活的单元格时,您会给它一个停用的点赞按钮,但是旧的、已激活的类似按钮仍然存在。

您不需要在每次需要单元格时都创建一个赞按钮,而应该只设置现有赞按钮的状态。请参阅this question 的答案,了解一些可能的处理方式。

【讨论】:

这只有在一次只显示一个单元格时才有效。更好的选择是将按钮添加到自定义单元格本身,而不是每次都插入一个。 嗯,没有。我从来没有说过一个像整个表格的按钮,而是一个像每个单元格的按钮。请注意,在 OP 的代码中,每次单元格被回收和重用时,都会添加另一个按钮。已重复使用五次的单元格将有五个按钮,彼此叠放。 谢谢,宇治。现在完全有道理,我不应该一直分配一个新按钮。只是为了亲眼看看,我随机选择了单元格内按钮的位置。当我上下滚动时,按钮到处都是。因此,根据您指出的其他答案,我需要扩展我当前的 uitableview 子类 (MyCustomViewCell) 以包含我需要的按钮和标签,并在 cellForRowAtIndexPath 中简单地使用它们。我不确定实现这一目标的最佳方法,但我会弄清楚的。感谢您的建议。【参考方案3】:

这是无效的(至少如果您试图比较字符串我的内容而不是地址):

if (myRating == @"9")

试试这个:

if ([myRating isEqualToString:@"9"])

感谢 yuji 注意到多个按钮的创建 +1。

【讨论】:

不错的 NJones。我的错。

以上是关于IOS:在uitableviewcell中保持按钮状态的主要内容,如果未能解决你的问题,请参考以下文章

获取 UITableViewCell 详细附件视图的图像

UITableViewCell 图像在上下滚动后发生变化,但 TextLabel 文本保持不变(iOS8,Swift)

iOS:Swift 中 UITableViewCell 的垃圾桶可以删除按钮

自定义 UITableViewCell 中的按钮在 iOS 7 中没有响应

在ios 7中,UITableViewCell Accessory DetailDisclosureButton分为两个不同的附件按钮

UITableViewCell 中的圆形按钮