1

我有一个包含自定义单元格的表格视图,它覆盖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];
}

我已经添加了日志和断点,并且正确的单元格正在将正确的选定状态发送给它。可能出了什么问题?

4

1 回答 1

0

事实证明,您不能依赖于立即调用零持续时间动画的完成块,这在您考虑时是有道理的。根据我的测试,完成的参数也总是YES如此。

尽管为不应该动画的过渡简单地设置为零的持续时间非常诱人,但如果动画包含完成块并且该方法被快速连续调用,则无法保证完成块的顺序叫进来。

例如,在上下滚动表格时,可能会发生以下情况:

  • 选定的单元格从屏幕上滚出并重新使用(选定:NO 动画:NO)
  • 选定的单元格滚动回到屏幕上(选定:YES 动画:NO)

使用零长度动画并不能保证第一次调用的完成块在第二次调用的完成块之前被调用。

一种解决方案是将动画操作和完成操作包装在两个本地块中,并直接执行这些操作或传递给动画,具体取决于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];
}

这具有额外的优势(对于更复杂的情况),不需要一个包含两个巨大代码块的大规模调用。如果您有嵌套动画,则更是如此。

于 2013-06-05T15:42:45.207 回答