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 单元格按钮