我有一个包含自定义单元格的tableview,它覆盖setSelected:animated:
。有时,当滚动包含所选单元格的表格时,所选单元格的外观是所选和未选定状态的奇怪混合。
我的setSelected:animated:
方法如下所示:
-(void)setSelected:(BOOL)selected animated:(BOOL)animated
{
if (selected == self.selected)
return;
CGFloat destinationAlpha = selected ? 1.0 : 0.0;
NSTimeInterval duration = animated ? 0.25 : 0.0;
for (UIView *view in self.topView.subviews)
{
if (![self.viewsToLeaveBackgroundAlone containsObject:view])
view.backgroundColor = [UIColor clearColor];
}
[UIView animateWithDuration:duration animations:^{
self.selectedTopViewBackground.alpha = destinationAlpha;
}animations completion:^(BOOL finished) {
if (!selected)
{
for (UIView *view in self.topView.subviews)
{
if (![self.viewsToLeaveBackgroundAlone containsObject:view])
view.backgroundColor = self.topView.backgroundColor;
}
}
}];
[super setSelected:selected animated:animated];
}
我添加了日志和断点,右侧单元格正在向其发送正确的选定状态。什么可能出错?
答案 0 :(得分:0)
事实证明,您不能立即调用零持续时间动画的完成块,这在您考虑它时是有意义的。根据我的测试,完成的参数也始终为YES
。
虽然简单地为不应该设置动画的过渡设置持续时间为零非常诱人,但如果动画包含完成块并且快速连续调用该方法,则无法保证顺序调用完成块。
例如,在向上和向下滚动表格时,可能会发生以下情况:
使用零长度动画并不能保证在第二次调用完成块之前调用第一次调用的完成块。
解决方案是将动画操作和完成操作包装在两个本地块中,并直接执行这些操作或传递给动画,具体取决于animated
参数:
-(void)setSelected:(BOOL)selected animated:(BOOL)animated
{
if (selected == self.selected)
return;
CGFloat destinationAlpha = selected ? 1.0 : 0.0;
for (UIView *view in self.topView.subviews)
{
if (![self.viewsToLeaveBackgroundAlone containsObject:view])
view.backgroundColor = [UIColor clearColor];
}
dispatch_block_t animations = ^{
self.selectedTopViewBackground.alpha = destinationAlpha;
};
dispatch_block_t completion = ^{
if (!selected)
{
for (UIView *view in self.topView.subviews)
{
if (![self.viewsToLeaveBackgroundAlone containsObject:view])
view.backgroundColor = self.topView.backgroundColor;
}
}
};
if (animated)
{
[UIView animateWithDuration:0.25 animations:animations completion:^(BOOL finished) { completion();}];
}
else
{
animations();
completion();
}
[super setSelected:selected animated:animated];
}
对于没有包含两个巨大代码块的大量调用,这具有额外的优势(对于更复杂的情况)。如果你有嵌套动画更是如此。