简体   繁体   English

IOS:维护uitableviewcell中的按钮状态

[英]IOS: Maintaining button state in uitableviewcell

I have an iPhone app problem that's been bugging me for a few days and it really doesn't seem like it should be this difficult so I'm sure I'm missing something obvious. 我有一个iPhone应用程序问题一直困扰我几天,它似乎不应该是这么困难,所以我敢肯定我错过了一些明显的东西。 I have researched plenty of forum discussions on "similar" topics but nothing that actually addresses this issue, specifically. 我已经研究过很多关于“类似”主题的论坛讨论,但实际上并没有解决这个问题。

To be clear, if there is some piece of documentation or some other source that I should research, please point me in the right direction. 需要说明的是,如果有一些文档或其他来源我应该研究,请指出正确的方向。

Here goes... 开始...

I have a list of items that I display to the user within a table (uitableview). 我有一个项目列表,我在表格中显示给用户(uitableview)。 The cell (uitableviewcell) for each item is custom and contains an image and a Like button (uibutton). 每个项目的单元格(uitableviewcell)是自定义的,包含图像和Like按钮(uibutton)。 As expected, for each item in the the table, the user can click the Like button or ignore it. 正如所料,对于表中的每个项目,用户可以单击“赞”按钮或忽略它。 The like button calls a separate process to update the server. like按钮调用单独的进程来更新服务器。 Simple, right? 简单吧?

So, here is the issue: 所以,这是问题:

When the Like button is clicked on a particular cell, the Selected state works fine but the moment you scroll the cell out of view, other random cells in the table show the Like button as Selected even though they were never touched. 当在特定单元格上单击“赞”按钮时,“选定”状态正常工作,但是当您将单元格滚出视图时,表格中的其他随机单元格将“相似”按钮显示为“已选择”,即使它们从未被触摸过。 Because the cells are reused, for obvious performance reasons, I understand why this could happen. 因为细胞被重复使用,出于明显的性能原因,我理解为什么会发生这种情况。 What I don't understand is why my approach (see code below) would not override or reset the button's state the way I think it should. 我不明白的是为什么我的方法(见下面的代码)不会像我认为的那样覆盖或重置按钮的状态。 For brevity, I am only including the relevant code here (hopefully formatted properly): 为简洁起见,我只在此处包含相关代码(希望格式正确):

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

So, I've been through many iterations of this but I can't seem to get the state of the button to show the Selected image for those items that are Liked and keep the normal image for those items that have not been Liked. 所以,我已经经历了很多迭代,但我似乎无法获得按钮的状态来显示所选项目的所选项目,并保留那些尚未被喜欢的项目的正常图像。

Any help or advice would be greatly appreciated. 任何帮助或建议将不胜感激。

there is a simple way out of this. 有一个简单的方法。 you can trick the button to keep being in the latest selected state. 你可以欺骗按钮以保持最新的选择状态。

make a mutable array, for the purpose of keeping the selected state of the button 创建一个可变数组,以保持按钮的选定状态

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"];
}

at the tableviewcell method, declare your button and set it so that it refers to the mutablearray to set it's selected state 在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;

and finally, create the method which the button triggered when the button is pressed, to change it's selected state 最后,创建按下按钮时按钮触发的方法,以更改其选定状态

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

The problem is that every time you create or reuse a cell you're giving it a new like button, so when you reuse a cell where the like button has been activated, you're giving it a deactivated like button but the old, activated like button is still there as well. 问题是,每次你创建或重复使用一个单元格时,你都会给它一个新的类似按钮,所以当你重复使用类似按钮被激活的单元格时,你会给它一个停用的按钮,但旧的,激活的像按钮仍然存在。

Instead of creating a like button every time you need a cell, you should just be setting the state of an existing like button. 您不必在每次需要单元格时创建类似按钮,而只需设置现有类似按钮的状态。 See the answers to this question for some possible ways of handling that. 有关处理此问题的一些可能方法,请参阅此问题的答案。

This is not valid (At least not if you are trying to compare strings my contents instead of addresses): 这是无效的(至少如果你试图比较字符串我的内容而不是地址):

if (myRating == @"9")

Try this: 尝试这个:

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

And +1 to yuji for noticing the multiple button creation. 和+1到yuji注意到多个按钮的创建。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM