旋转 UITableView 时更新 UITableViewCells 的问题

Posted

技术标签:

【中文标题】旋转 UITableView 时更新 UITableViewCells 的问题【英文标题】:Problem updating UITableViewCells when rotating UITableView 【发布时间】:2010-09-08 18:33:22 【问题描述】:

我在自定义 UITableViewCell 中有一个 UILabel,它会在设备旋转时调整大小。此标签中的文本需要在旋转后重新计算,因为我正在将其缩小并在末尾附加一些文本。

例如数据模型有:“这是一个需要停止的连续句子。”

在纵向模式下,它变成“这是一个连续发送...更多”

在横向模式下,它变成“这是一个连续的句子……更多”

来自(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation 我能够访问可见的 UITableViewCells 并更新描述。

问题似乎是有 UITableViewCells 被缓存但我无法访问。当我在旋转后滚动 UITableView 时,旋转后可见区域下方的一两个单元格在标签中没有正确的文本。所以它们没有通过(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 呈现 - 但它们不是由 [tableView visibleCells] 返回(或通过循环通过 [tableView subViews] 返回的所有视图)。

我已尝试通过此方法访问“额外”单元格:

for (int index=max + 1; index < max + 3 && index < [cellTypes count]; index++) 
    NSIndexPath *updatedPath = [NSIndexPath indexPathForRow:index inSection:0];
    UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:updatedPath];
    if (cell == nil)  continue; 
    [self updateCellForRotate:cell forRow:index];

(其中 max 是从 visibleCells 返回的最大行)但单元格始终为零。

有没有办法刷新 UITableViewCells 的缓存,以免它们被重复使用?或者访问它们以便我可以更新它们?

谢谢!

【问题讨论】:

【参考方案1】:

两件事。 第一的。在您的 didRotateFromInterfaceOrientation 方法中,您可以像这样简单地重新加载可见行:

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation) fromInterfaceOrientation

    [super didRotateFromInterfaceOrientation:fromInterfaceOrientation];

    NSLog(@"didRotateFromInterfaceOrientation:%d",fromInterfaceOrientation);
    [tableView reloadRowsAtIndexPaths:[tableView indexPathsForVisibleRows] withRowAnimation:UITableViewRowAnimationNone];

然后我建议您将interfaceOrientation 数字或简单的表格宽度添加到出列单元格名称中,这样tableView 就知道一个轮换中的单元格与另一轮中的单元格不同。像这样:

- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath withType:(NSString *)s_type

    UITableViewCell *cell = nil;
    // add width of table to the name so that rotations will change the cell dequeue names
    s_cell = [s_cell stringByAppendingString:[NSString stringWithFormat:@"%@%d",@"Width",(int)tv.bounds.size.width]];

    NSLog(@"%@",s_cell);
    cell = [tv dequeueReusableCellWithIdentifier:s_cell];
    if( cell == nil )  
        cell = [[[UITableViewCell alloc];
        initWithFrame:CGRectZero reuseIdentifier:s_cell] autorelease];
    

【讨论】:

FWIW,didRotateFromInterfaceOrientation: 的实现应该调用 super.【参考方案2】:

首先,要重新加载所有表格单元格,请使用 [self.tableView reloadData]

其次,在(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath方法内部添加负责收缩的代码行。

例子:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
    //Some identifier and recycling stuff

    if (UIInterfaceOrientationIsPortrait(self.interfaceOrientation)) 
        //Make labels smaller
    
    else 
        //Make them bigger
    

或者你可以在制作它们时调用你的updateCellForRotate:forRow: 方法。但我不确定这个函数是如何工作的,所以我不能太具体。

【讨论】:

确实在方向改变时重新创建所有单元格会导致性能下降吗?我可能是错的(众所周知);) 是的,“cellForRowAtIndexPath”似乎没有这样做。 reloadData 也没有 - 应该在我的原件中发布。将调查 updateCellForRotate - 它们是来自 xibs 的自定义单元格。 如果您正在回收您的单元格(这是管理表上内存的最佳方式!)重新加载数据是您想要做的,因为用您自己的术语“刷新缓存” .如果你不回收细胞,这是一个更大的野兽,所以你必须手动重绘每个。 我正在回收细胞。 [tableview reloadData] 似乎确实可以很好地更新所有可见的单元格,但是当我向下滚动时,我仍然遇到问题显示一两个单元格。 我刚刚将我的实现更改为 [self.tableView reloadData] ,这让我准确地到达了我在一行中的位置。直到用户滚动到单元格,离开然后再次返回之前,问题仍然存在。希望他们不会注意到。 :-S 感谢您的帮助!【参考方案3】:

当您在cellForRowAtIndexPath: 中创建单元格时,将其添加到数组中。然后,遍历数组,根据需要更新文本。

希望这会有所帮助, jrtc27

编辑:

你说它们是自定义单元格 - 你能不更新你的 UITableViewCell 子类中的文本吗?

【讨论】:

啊......我完全认为这会奏效。似乎没有。我想知道此时它是否还没有旋转单元格(我正在表格视图控制器“didRotateFrom...”中进行更新)请注意,它确实像我以前的方法一样更新了可见单元格。我想这一定是单元格在显示之前不会旋转。 好吧,我还没有解决它,但我用你的数组想法打印出调试器中的所有单元格......看起来长度标签不正确的单元格有尺寸错误。【参考方案4】:

所以,我最近遇到了(我认为是)一个非常相似的问题,并且发布的答案都没有帮助我,很抱歉。

我的问题是我在旋转时故意调整了 UITableView 的大小和位置,并且我以编程方式进行了操作。纵向中的表格单元占据了视图的宽度,而横向中的表格单元格更高但宽度更小。然后我根据我们要达到的方向重新定位单元格的元素。

在应用程序启动时,第一次查看表格很好。然后我旋转并发现我似乎有一些元素的两个实例,这些似乎是第一个表格中单元格可见的位置。向后旋转会破坏带有前一个表中的元素的初始方向表。

我尝试了上面所有适用的答案,直到我仔细查看了 cellForRowAtIndexPath 代码:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) 
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];

我知道细胞重复使用是一个好主意,但我真的不需要保留(如保存)任何细胞,并希望它们在每次旋转后都明亮、闪亮和新。

编辑:在我自己的应用程序中,我最多可能有 20-30 行,因为我个人不喜欢非常长的表格。如果要为特定查询返回大量行,我会为用户提供一些过滤器来帮助他们整理出他们想要的行。如果您要显示大量行,则将它们出列可能会导致您不希望的性能影响。

我所做的只是注释掉 if 和以下括号,我的表格单元格完全按照我的意愿更新:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
//if (cell == nil) 
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
//

为华夫饼道歉,以及对一个老问题的迟到回答。

本。

华夫饼和奶油,或糖浆。

【讨论】:

你还不如摆脱 dequeue 调用。但是如果你有大量的行,我不会推荐你在做什么,那将是内存中的很多单元格。我脑海中突然出现的事情是尝试检查方向并为每个方向设置不同的单元格标识符。这样,单元格只会在预期的方向上重复使用(并确保在旋转后重新加载数据)。 是的,如果表格单元格的内容很大(内存方面),那么不重复使用可能会导致性能下降或内存泄漏,您无法承受或控制。我已经更新了我的答案,谢谢!【参考方案5】:

您可以在 shouldAutorotateToInterfaceOrientation 方法中使用这条简单的线:

self.view.autoresizesSubviews = YES;

对我来说,它总是成功地工作

【讨论】:

shouldAutorotateToInterfaceOrientation: 似乎是一个奇怪的地方。你有什么理由不在viewDidLoad 中这样做?在 shouldAutorotateToInterfaceOrientation: 中,您应该只确定您的 viewController 是否应该旋转。

以上是关于旋转 UITableView 时更新 UITableViewCells 的问题的主要内容,如果未能解决你的问题,请参考以下文章

UITableView Space 3 UITableViewCells 均匀分布在整个设备框架上

在 iOS 的 UITableViewCell 中更新 UIButton 图像时发生冲突

UITableView滚动式cell错位

在 iOS 13 中,tableView 中 UIDatePicker 的无效更新在旋转时崩溃

UITableView 复选标记重复

调整 UITableView 高度(嵌入在 UIScrollView 中)