使用reloadRowsAtIndexPaths重新加载时,为什么我的表视图单元格会消失?

Tig*_*ing 19 iphone objective-c uitableview ios

我这里有一个简单的示例项目:

http://dl.dropbox.com/u/7834263/ExpandingCells.zip

在这个项目中,UITableView有一个自定义的UITableViewCell.在每个单元格中有3个包含标签的UIViews.

目标是在敲击时扩展单元格,然后在再次敲击时将其折叠.单元格本身必须更改其高度以显示子视图.插入或删除行是不可接受的.

演示项目几乎按预期工作.事实上,在iOS 4.3中,它的工作非常完美.然而,在iOS 5下,当行崩溃时,先前的单元格神奇地消失.

要重新创建问题,请在iOS 5的模拟器或设备中运行项目,然后点击第一个单元格以展开它.然后再次点击该单元格以折叠它.最后,直接点击它下面的单元格.前一个消失了.

继续点击该部分中的每个单元格将导致所有单元格消失,直到整个部分缺失的位置.

我也尝试使用reloadData而不是当前的设置,但这会破坏动画并且感觉有点像黑客.reloadRowsAtIndexPaths应该可以工作,但问题是为什么不呢?

查看下面发生的事情的图像:

表格出现:

表出现了

细胞扩展:

表扩展

细胞塌陷:

桌子倒塌了

细胞消失(当敲击下面的细胞时):

细胞消失了

不断重复,直到整个部分消失:

部分消失了

编辑: 覆盖alpha是一个黑客,但有效.这是另一个"黑客"修复它,但为什么它修复它?

JVViewController.m第125行:

if( previousIndexPath_ != nil )
{
    if( [previousIndexPath_ compare:indexPath] == NSOrderedSame ) currentCellSameAsPreviousCell = YES;

    JVCell *previousCell = (JVCell*)[self cellForIndexPath:previousIndexPath_];

    BOOL expanded = [previousCell expanded];
    if( expanded )
    {
        [previousCell setExpanded:NO];
        [indicesToReload addObject:[previousIndexPath_ copy]];
    }
    else if( currentCellSameAsPreviousCell )
    {
        [previousCell setExpanded:YES];
        [indicesToReload addObject:[previousIndexPath_ copy]];
    }

    //[indicesToReload addObject:[previousIndexPath_ copy]];
}
Run Code Online (Sandbox Code Playgroud)

编辑2:

对演示项目做了一些小改动,值得检查并查看JVViewController didSelectRowAtIndexPath方法.

小智 21

您的问题出在setExpanded:在JVCell.m中,您正在直接编辑该方法中目标单元格的框架.

- (void)setExpanded:(BOOL)expanded
{
    expanded_ = expanded;

    CGFloat newHeight = heightCollapsed_;
    if( expanded_ ) newHeight = heightExpanded_;

    CGRect frame = self.frame;
    frame.size.height = newHeight;
    self.frame = frame;
}
Run Code Online (Sandbox Code Playgroud)

将其更新为:

- (void)setExpanded:(BOOL)expanded
{
    expanded_ = expanded;
}
Run Code Online (Sandbox Code Playgroud)

然后删除-reloadRowsAtIndexPaths:withRowAnimation:对JVViewController.m的第163行的调用,它将按预期动画.

-reloadRowsAtIndexPaths:withRowAnimation:期望为提供的indexPaths返回不同的单元格.由于您只调整尺寸-beginUpdates-endUpdates足以重新布局表格视图单元.

  • 作为旁注,alpha被设置为零的原因是因为该表将一个单元视为旧单元和新单元.表视图的行为是将旧单元格淡出其后面的新单元格.所以它的alpha被设置为1作为"新"单元,但随后作为"旧"单元从1变为零. (2认同)

Den*_*cik 10

可能是我错过了一点,但为什么不用你:

UITableViewRowAnimationNone

我的意思是代替:

[tableView reloadRowsAtIndexPaths:indicesToReload withRowAnimation:UITableViewRowAnimationAutomatic];
Run Code Online (Sandbox Code Playgroud)

使用

[tableView reloadRowsAtIndexPaths:indicesToReload withRowAnimation:UITableViewRowAnimationNone];
Run Code Online (Sandbox Code Playgroud)


Col*_*lin 8

要为tableView的高度更改设置动画,只需调用即可.

[tableView beginUpdates];
[tableView endUpdates];
Run Code Online (Sandbox Code Playgroud)

不要调用reloadRowsAtIndexPaths:

请参阅选中时,是否可以在UITableViewCell上设置高度更改动画?


Nat*_*ger 5

淡出的单元格是不改变大小的前一个单元格.作为国家的文件reloadRowsAtIndexPaths:withRowAnimation::

该表动画化了新单元格,因为它为旧行设置了动画.

会发生什么是不透明度设置为1然后立即设置为0,因此淡出.

如果先前和新单元格都改变了大小,那么它按预期工作.这是因为开始/结束更新会注意到高度的变化,并在那些覆盖那些单元格的单元格上创建新的动画reloadRowsAtIndexPaths:withRowAnimation:.

您的问题是由于在reloadRowsAtIndexPaths:withRowAnimation:用于加载新单元格时滥用单元格的大小.

但你根本不需要reloadRowsAtIndexPaths:withRowAnimation:.只需更改单元格的展开状态并执行开始/结束更新.这将为您处理所有动画.

作为旁注,我发现蓝色选择有点烦人,在JVCell中将selectedBackgroundView设置为与backgroundView相同的图像(或创建具有所选单元格的正确外观的新图像).


编辑:

将添加语句previousIndexPath_indicesToReloadif语句(以线132),这样,如果前一小区扩大,需要调整其大小只添加.

if( expanded ) {
    [previousCell setExpanded:NO];
    [indicesToReload addObject:[previousIndexPath_ copy]];
}
Run Code Online (Sandbox Code Playgroud)

这消除了先前折叠的单元格将消失的情况.

另一种选择是previousIndexPath_在当前单元格折叠时设置为nil,仅在单元格展开时设置为nil.

这仍然感觉像是一个黑客.同时执行reloadRows和开始/结束更新会导致tableView重新加载所有内容两次,但似乎都需要正确设置动画.我想如果表格不是太大,这不会是性能问题.