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

如何保存UIProgressView动画状态并恢复?中途重置动画怎么做?

问题1:后台暂停后前台恢复动画消失的解决方法

当APP进入后台时,系统会暂停甚至移除UIKit动画,仅靠操作layer的timeOffset和speed无法恢复已被系统清理的动画。正确的做法是保存当前动画的进度状态,回到前台时基于保存的进度重新创建动画。

实现步骤:

  1. 添加变量保存当前进度和剩余动画时长:
private var currentProgress: Float = 0
private var remainingAnimationDuration: TimeInterval?
private let totalAnimationDuration: TimeInterval = 5 // 与启动方法的总时长保持一致
  1. 修改暂停方法,保存当前显示的进度和剩余时长:
func pauseProgressAnimation() {
    // 获取动画实时显示的进度(presentationLayer对应当前屏幕上的视觉状态)
    guard let presentationLayer = progressView.layer.presentation() as? UIProgressViewLayer else { return }
    currentProgress = presentationLayer.progress
    
    // 计算剩余动画时长
    let elapsedRatio = TimeInterval(currentProgress)
    remainingAnimationDuration = totalAnimationDuration * (1 - elapsedRatio)
    
    // 清除当前动画并重置layer状态
    progressView.layer.removeAllAnimations()
    progressView.layer.speed = 1
    progressView.layer.timeOffset = 0
    progressView.layer.beginTime = 0
    
    // 将视图进度同步到当前保存的进度值
    progressView.setProgress(currentProgress, animated: false)
}
  1. 修改恢复方法,基于保存的进度重新启动动画:
func resumeProgressAnimation() {
    guard let remainingDuration = remainingAnimationDuration, currentProgress < 1 else {
        // 若进度已完成或无剩余时长,重新启动完整动画
        startProgressAnimation()
        return
    }
    
    // 从保存的进度点开始剩余时长的动画
    progressView.setProgress(currentProgress, animated: false)
    UIView.animate(withDuration: remainingDuration, options: .curveLinear) {
        self.progressView.setProgress(1, animated: true)
    } completion: { [weak self] finished in
        if finished {
            self?.delegate?.scrollToNextStory()
        }
    }
}
  1. 优化启动方法,支持从指定进度开始:
func startProgressAnimation(fromProgress: Float = 0) {
    currentProgress = fromProgress
    remainingAnimationDuration = totalAnimationDuration * TimeInterval(1 - fromProgress)
    
    progressView.setProgress(fromProgress, animated: false)
    UIView.animate(withDuration: remainingAnimationDuration!, delay: 0, options: .curveLinear) {
        self.progressView.setProgress(1, animated: true)
    } completion: { [weak self] finished in
        if finished {
            self?.delegate?.scrollToNextStory()
        }
    }
}

问题2:动画中途重置并重新播放的正确实现

你当前的resetProgress方法思路正确,但可以简化优化,确保彻底清除动画状态并重置进度:

优化后的重置方法:

func resetProgress() {
    // 清除所有动画(包括子层的进度动画)
    progressView.layer.removeAllAnimations()
    
    // 重置layer时间相关属性,避免残留状态影响后续动画
    progressView.layer.speed = 1
    progressView.layer.timeOffset = 0
    progressView.layer.beginTime = 0
    
    // 无动画地将进度重置到初始状态
    progressView.setProgress(0, animated: false)
    
    // 若需要重置后立即重新播放,取消下面的注释
    // startProgressAnimation()
}

说明:

  • 无需遍历子层移除动画,progressView.layer.removeAllAnimations()会自动清除所有子层的动画。
  • 重置layer的speed、timeOffset、beginTime是为了避免之前的暂停/恢复操作残留状态,导致后续动画异常。
  • 如果需要重置后立即启动动画,直接调用startProgressAnimation()即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 14:52:50