You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Cell复用后恢复CAAnimation Group动画?

解决Cell复用后CAAnimation无法恢复的问题

我之前也踩过一模一样的坑!你说的没错,苹果官方QA1673的暂停/恢复方法只适用于你主动暂停的动画,而Cell滚出屏幕时,系统是主动终止了动画(从animationDidStop:finished:的flag=YES就能明确看出来),这时候已停止的动画根本没法直接恢复,必须换个思路:保存动画进度,复用Cell时重新创建动画并从断点续跑。

下面是我实测有效的方案,分两步走:

1. 在Cell即将被复用时,记录当前动画进度

不管是在Cell的prepareForReuse方法,还是TableView的didEndDisplayingCell代理方法里,我们都可以捕获动画的当前运行进度,然后移除旧动画(避免复用冲突)。

先给你的自定义Cell加个属性用来存进度:

@property (nonatomic, assign) CGFloat animationProgress;

然后在prepareForReuse里记录进度:

- (void)prepareForReuse {
    [super prepareForReuse];
    
    NSString *animationKey = @"YourUniqueAnimationKey"; // 给你的动画设个唯一Key
    if ([self.layer animationForKey:animationKey]) {
        CAAnimation *anim = [self.layer animationForKey:animationKey];
        // 计算当前进度:已运行时间 / 动画总时长
        CFTimeInterval currentTime = [self.layer convertTime:CACurrentMediaTime() fromLayer:nil];
        CFTimeInterval elapsedTime = currentTime - self.layer.beginTime;
        self.animationProgress = elapsedTime / anim.duration;
        
        // 把进度限制在0~1之间,避免异常值
        self.animationProgress = MAX(0.0, MIN(1.0, self.animationProgress));
        
        // 移除旧动画
        [self.layer removeAnimationForKey:animationKey];
    }
}

2. 复用Cell时,从保存的进度重新启动动画

在你给Cell配置数据的方法里(比如configureWithModel:),重新创建动画,并根据之前保存的进度设置起始时间,让动画从断点继续:

- (void)configureWithModel:(YourModel *)model {
    // 先做你的数据配置逻辑...
    
    NSString *animationKey = @"YourUniqueAnimationKey";
    [self.layer removeAnimationForKey:animationKey]; // 保险起见,先移除旧动画
    
    // 创建你的CAAnimation(这里以CABasicAnimation为例,换成你自己的动画类型即可)
    CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
    anim.fromValue = @0.8;
    anim.toValue = @1.2;
    anim.duration = 1.5;
    anim.repeatCount = HUGE_VALF; // 无限重复
    anim.autoreverses = YES;
    anim.fillMode = kCAFillModeForwards;
    anim.removedOnCompletion = NO;
    
    // 如果有保存的进度,设置动画的起始时间
    if (self.animationProgress > 0) {
        // 计算需要跳过的时间:总时长 × 已完成进度
        CFTimeInterval skipTime = anim.duration * self.animationProgress;
        // 设置图层的beginTime,让动画从指定进度开始
        self.layer.beginTime = CACurrentMediaTime() - skipTime;
    } else {
        // 没有进度记录,重置图层时间属性
        self.layer.beginTime = 0;
    }
    
    // 添加动画到图层
    [self.layer addAnimation:anim forKey:animationKey];
    
    // 重置进度,避免影响下次复用
    self.animationProgress = 0.0;
}

关键注意点

  • 一定要给动画设置唯一的Key,这样才能准确获取和移除对应的动画;
  • 动画的removedOnCompletion设为NO,fillMode设为kCAFillModeForwards,确保动画状态能保留;
  • 不要在Cell的init或awakeFromNib里添加动画,必须在配置数据的方法里动态创建,这样复用的时候才能灵活控制。

为什么QA1673的方法没用?因为系统终止动画后,动画的finished状态已经被设为YES,此时无论怎么调整图层的speed、timeOffset,都没法让一个已完成的动画重新运行,只能重新创建并续跑。

内容的提问来源于stack exchange,提问作者Huanrong

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:38:23