当单元格高度动态更改时,UITableView 出现不自然的混蛋
Posted
技术标签:
【中文标题】当单元格高度动态更改时,UITableView 出现不自然的混蛋【英文标题】:Unnatural jerk with UITableView whe cell height is changed dynamically 【发布时间】:2013-07-09 06:31:24 【问题描述】:这是我想要的应用程序。下图是iPhone应用商店的两张截图:
我基本上需要一个 “阅读更多” 功能,就像它在应用商店中使用的一样(参见上面两张图片中的 “说明” 部分)。我假设这里的每个部分(Description、What's New、Information 等)都是一个表格视图单元格。而里面的文字是一个UILabel或者UITextField。
这是我迄今为止尝试添加此功能的方法:
NSString *initialText = @"Something which is not a complete text and created just as an example to...";
NSString *finalText = @"Something which is not a complete text and created just as an example to illustrate my problem here with tableviews and cel heights. bla bla bla";
NSInteger isReadMoreTapped = 0;
我的 cellForRowAtIndexPath 函数:
// Other cell initialisations
if(isReadMoreTapped==0)
cell.label.text = initialText;
else
cell.label.text = finalText;
return cell;
我的 heightForRowAtIndexPath 函数:
// Other cell heights determined dynamically
if(isReadMoreTapped==0)
cell.label.text = initialText;
cellHeight = //Some cell height x which is determined dynamically based on the font, width etc. of the label text
else
cell.label.text = finalText;
cellHeight = //Some height greater than x determined dynamically
return cellHeight;
最后是我的 IBAction readMoreTapped 方法,该方法在点击 More 按钮时调用:
isReadMoreTapped = 1;
[self.tableView beginUpdates];
[self.tableView endUpdates];
NSIndexPath* rowToReload = [NSIndexPath indexPathForRow:2 inSection:0]; // I need to reload only the third row, so not reloading the entire table but only the required one
NSArray* rowsToReload = [NSArray arrayWithObjects:rowToReload, nil];
[self.tableView reloadRowsAtIndexPaths:rowsToReload withRowAnimation:UITableViewRowAnimationNone];
完成所有这些之后,我确实获得了所需的功能。计算该特定单元格的新高度并将新文本加载到其中。 但是 TableView 上有一个非常不自然的混蛋,这会导致糟糕的用户体验。但是,应用商店 More 按钮并非如此。在它的情况下没有不自然的混蛋。 TableView 保持原位,只有更改的单元格的大小随着文本的平滑显示而增加。
如何实现iPhone应用商店更多按钮的流畅度?
【问题讨论】:
你有没有尝试过reload方法中的其他行动画? 你能描述一下“混蛋”吗?尺寸是否仍然动画到新值?它是滚动位置的一个混蛋,单元格的内容? @LithuT.V 是的,我有。行为没有变化 @jrturton 高度动画到新值,但滚动位置有一个混蛋。我认为出现问题是因为我再次使用[self.tableView beginUpdates];
和[self.tableView endUpdates];
重新计算了所有单元格的高度
【参考方案1】:
您的问题可能来自重新加载行。您想尝试直接配置单元格属性。我通常使用专用方法来配置我的单元格内容,因此我不必重新加载行。
- (void)configureCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
if(isReadMoreTapped==0)
cell.label.text = initialText;
else
cell.label.text = finalText;
// all other cell configuration goes here
此方法从 cellForRowAtIndexPath 方法中调用,它将配置单元格
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
[self configureCell:cell forRowAtIndexPath:indexPath];
return cell;
你会直接调用这个方法来避免重新加载:
isReadMoreTapped = 1;
[self.tableView beginUpdates];
[self.tableView endUpdates];
NSIndexPath* rowToReload = [NSIndexPath indexPathForRow:2 inSection:0];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:rowToReload];
[self configureCell:cell forRowAtIndexPath:rowToReload];
【讨论】:
让我试一试,结果会尽快回复您 嗯,它几乎解决了我的问题。但我不知道为什么它也会改变其他细胞的高度。当我点击 More 按钮时,所需单元格的高度增加并且其文本得到更新;同时,该单元格上方的单元格高度存在异常行为(主要是它们的高度降低)。在我的heightForRowAtIndexPath
中,我通过使用sizeWithFont: constrainedToSize: lineBreakMode:
方法估计标签的大小来动态计算单元格的高度
终于解决了我的问题!部分与您提供的内容有关,部分与其他 SO 帖子有关。将尽快更新答案
不会调用 [self.tableView beginUpdates];和 [self.tableView endUpdates];仍然导致表重新加载和抖动?【参考方案2】:
请尝试对您的代码进行以下更改,我认为它会解决您的问题。
无需在heightForRowAtIndexPath
中设置cell.label.text
;请删除它们。
在readMoreTapped
,更新表就够了:
isReadMoreTapped = 1;
[self.tableView beginUpdates];
[self.tableView endUpdates];
【讨论】:
【参考方案3】:要么删除调用:
[self.tableView beginUpdates];
[self.tableView endUpdates];
或更改以确保您的重新加载代码在它们之间。我会删除它们,因为您使用的方法可以很好地处理单行重新加载:
[self.tableView reloadRowsAtIndexPaths:rowsToReload withRowAnimation:UITableViewRowAnimationNone];
你只需要指定一个像fade这样的行动画。
【讨论】:
【参考方案4】:好的,我终于在 Matthias 的答案(已接受的答案)和我自己的优化的帮助下解决了这个问题。绝对应该做的一件事是创建一个像 configureCell: forRowAtIndexPath:
这样的专用函数来直接配置单元格属性(参见 Mathias 的回答)。一切都与马蒂亚斯的回答一样除了:
之前,每次调用heightForRowAtIndexPath
函数时我都在计算每个单元格的高度,而没有在任何地方缓存(保存)它们,因此当[self.tableView beginUpdates];
和[self.tableView endUpdates];
被调用时,每个单元格的高度都会再次计算。相反,您需要做的是将这些单元格高度保存在一个数组/字典中,以便每当点击 More 按钮时,您只计算已更改单元格的高度。对于其他单元格,只需查询数组/字典并返回保存的单元格高度。这应该可以解决单元格高度更新后 tableView 滚动的任何问题。如果还有其他人遇到与此类似的问题,请在此帖子下发表评论。我很乐意提供帮助
【讨论】:
以上是关于当单元格高度动态更改时,UITableView 出现不自然的混蛋的主要内容,如果未能解决你的问题,请参考以下文章
UITableView:单击按钮时如何动态更改单元格高度?迅速
如何在 Swift 中动态更改包含 UICollectionView 单元格的 UITableView 单元格的高度?
UITableView 自定义单元格高度未正确管理 swift 中的动态约束