Iphone 为什么我的表视图单元格在使用reloadRowsAtIndexPaths重新加载时会消失?
我这里有一个简单的示例项目: 在此项目中,UITableView具有自定义UITableViewCell。每个单元格中有3个包含标签的UIView 目标是在点击时使细胞膨胀,然后在再次点击时将其折叠。单元本身必须更改其高度才能显示子视图。不能插入或删除行 演示项目几乎如预期的那样工作。事实上,在iOS 4.3中,它工作得非常完美。然而,在iOS5下,当行崩溃时,前面的单元格神奇地消失了 要重新创建问题,请在具有iOS 5的模拟器或设备中运行项目,然后点击第一个单元格以展开它。然后再次轻敲该单元格以将其折叠。最后,直接点击下方的单元格。前一个消失了 继续敲击该部分中的每个单元格将导致所有单元格消失,直至整个部分丢失 我也尝试过使用重载数据而不是当前的设置,但这会破坏动画,而且感觉有点像黑客。重新加载rowsatindexpaths应该可以工作,但问题是为什么不能呢 请参见下面发生的事情的图片: 下表显示: 单元格展开: 单元格崩溃: 单元格消失(轻敲下方的单元格时): 继续重复,直到整个部分消失: 编辑: 覆盖alpha是一种黑客行为,但有效。这里有另一个“黑客”也能修复它,但为什么它能修复它呢 JVViewController.m第125行:Iphone 为什么我的表视图单元格在使用reloadRowsAtIndexPaths重新加载时会消失?,iphone,objective-c,ios,uitableview,Iphone,Objective C,Ios,Uitableview,我这里有一个简单的示例项目: 在此项目中,UITableView具有自定义UITableViewCell。每个单元格中有3个包含标签的UIView 目标是在点击时使细胞膨胀,然后在再次点击时将其折叠。单元本身必须更改其高度才能显示子视图。不能插入或删除行 演示项目几乎如预期的那样工作。事实上,在iOS 4.3中,它工作得非常完美。然而,在iOS5下,当行崩溃时,前面的单元格神奇地消失了 要重新创建问题,请在具有iOS 5的模拟器或设备中运行项目,然后点击第一个单元格以展开它。然后再次轻敲该单元
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]];
}
编辑2:
对演示项目进行了一些小的更改,值得检查和查看JVViewController的didSelectRowAtIndexPath方法。我刚刚下载了您的项目,并在使用了
重新加载Rowatindexpath的didSelectRowAtIndexPath
委托中找到了这段代码
[tableView reloadRowsAtIndexPaths:indicesToReload withRowAnimation:UITableViewRowAnimationAutomatic];
[tableView beginUpdates];
[tableView endUpdates];
你为什么不试试这个呢
[tableView beginUpdates];
[tableView reloadRowsAtIndexPaths:indicesToReload withRowAnimation:UITableViewRowAnimationAutomatic];
[tableView endUpdates];
我之所以建议这样做,是因为我相信,reloadRowsAtIndexPaths:…
仅在对以下对象的调用之间进行包装时有效:
- (void)beginUpdates;
- (void)endUpdates;
除此之外,行为是未定义的,正如您所发现的,相当不可靠。引用“”的有关部分:
若要为行和节的批量插入和删除设置动画,请在通过连续调用BeginUpdate和EndUpdate定义的动画块中调用插入和删除方法。如果不在此块中调用插入和删除方法,则行和节索引可能无效。BeginUpdate…EndUpdate块不可嵌套
在块结束时,即endUpdates返回后,表视图照常查询其数据源并委托行和节数据。因此,支持表视图的集合对象应该更新以反映新的或删除的行或节
iPhone OS 3.0中引入的ReloadSection:withRowAnimation:和ReloadRowsAndExpaths:withRowAnimation:方法与上面讨论的方法相关。它们允许您请求表视图重新加载特定节和行的数据,而不是通过调用reloadData加载整个可见表视图
可能还有其他合理的原因,但让我仔细考虑一下,因为我也有你的代码,我可以到处乱搞。希望我们能找到答案…@Javy,我在测试你的应用程序时注意到一些奇怪的行为
在iPhone 5.0模拟器上运行时先前的INDExpth_uuu变量为
类NSArray
(看起来像。)以下是调试器输出
(lldb) po previousIndexPath_
(NSIndexPath *) $5 = 0x06a67bf0 <__NSArrayI 0x6a67bf0>(
<JVSectionData: 0x6a61230>,
<JVSectionData: 0x6a64920>,
<JVSectionData: 0x6a66260>
)
(lldb) po [previousIndexPath_ class]
(id) $7 = 0x0145cb64 __NSArrayI
你知道这个问题吗?不确定这是否有帮助,但考虑让您知道。简短而实用的回答:将UITableViewRowAnimationAutomatic
更改为UITableViewRowAnimationTop
解决了这个问题。不再有消失的行!(在iOS 5.1上测试)
另一个简短而实用的答案,因为据说UITableViewRowAnimationTop会引起它自己的问题:创建一个新的单元视图,而不是修改现有的框架。在一个真实的应用程序中,单元视图中显示的数据无论如何都应该在应用程序的模型部分,因此,如果设计得当,创建另一个仅以不同方式显示相同数据的单元视图(在本例中为框架)应该不会有问题
有关为同一单元格重新加载设置动画的更多想法:
UITableViewRowAnimationAutomatic
在某些情况下似乎会分解为UITableViewRowAnimationFade
,即当您看到单元格逐渐消失时。新电池应该淡入,而旧电池应该淡出。但在这里,旧的细胞和新的细胞是一个和相同的-所以,这甚至可以工作吗?在核心动画级别,是否可以淡出视图并同时淡入?听起来可疑。因此,结果就是你只看到淡出。这可能被认为是一个Apple bug,因为预期的行为可能是,如果相同的视图发生了更改,alpha属性将不会被设置动画(因为它不能同时设置为0和1),而是只设置帧、颜色等的动画
请注意,问题只出现在动画的显示中-如果您来回滚动,所有内容都将正确显示
在iOS 4.3中,自动
模式可能已被解析为除淡入
之外的其他模式,这就是为什么在那里工作的原因(正如你所写的那样)-我没有深入研究
我不知道为什么iOS会选择淡入淡出模式。但其中一种情况是,当您的代码请求重新加载以前点击的单元格时,该单元格已折叠,并且与当前点击的单元格不同。注意:以前点击的单元格总是被重新加载,代码中的这一行总是被调用:
[indicesToReload addObject:[previousIndexPath_ copy]];
这就解释了失踪的魔力
[indicesToReload addObject:[previousIndexPath_ copy]];
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationTop];
}
if( expanded ) {
[previousCell setExpanded:NO];
[indicesToReload addObject:[previousIndexPath_ copy]];
}
[tableView reloadRowsAtIndexPaths:indicesToReload withRowAnimation:UITableViewRowAnimationAutomatic];
[tableView reloadRowsAtIndexPaths:indicesToReload withRowAnimation:UITableViewRowAnimationNone];
- (void)setExpanded:(BOOL)expanded
{
expanded_ = expanded;
CGFloat newHeight = heightCollapsed_;
if( expanded_ ) newHeight = heightExpanded_;
CGRect frame = self.frame;
frame.size.height = newHeight;
self.frame = frame;
}
- (void)setExpanded:(BOOL)expanded
{
expanded_ = expanded;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
BOOL currentCellSameAsPreviousCell = NO;
NSMutableArray *indicesToReload = [NSMutableArray array];
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];
}
else if (currentCellSameAsPreviousCell)
{
[previousCell setExpanded:YES];
}
[indicesToReload addObject:[previousIndexPath_ copy]];
if (expanded)
previousIndexPath_ = nil;
else
previousIndexPath_ = [indexPath copy];
}
if(currentCellSameAsPreviousCell == NO)
{
JVCell *currentCell = (JVCell*)[self cellForIndexPath:indexPath];
BOOL expanded = [currentCell expanded];
if(expanded)
{
[currentCell setExpanded:NO];
previousIndexPath_ = nil;
}
else
{
[currentCell setExpanded:YES];
previousIndexPath_ = [indexPath copy];
}
// moving this line to inside the if statement blocks above instead of outside the loop works, but why?
[indicesToReload addObject:[indexPath copy]];
}
// commenting out this line makes the animations work, but the table view background is visible between the cells
[tableView reloadRowsAtIndexPaths:indicesToReload withRowAnimation:UITableViewRowAnimationAutomatic];
// using reloadData completely ruins the animations
[tableView beginUpdates];
[tableView endUpdates];
}
- (void) refreshTableViewCell:(NSNumber *)row
{
if (![[NSThread currentThread] isMainThread])
{
[self performSelector:_cmd onThread:[NSThread mainThread] withObject:row waitUntilDone:NO];
return;
}
/*Refresh your cell here
...
*/
}
[tableView beginUpdates];
[tableView endUpdates];
override func tableView(tableView: UITableView,heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if ( indexPath.row == 2){
resetIndexPath.append(indexPath)
if resetPassword.on {
// whatever height you want to set the row to
return 125
}
}
return 44
}
@IBAction func resetPasswordSwitch(sender: AnyObject) {
tableView.reloadData()
}