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

UIProgressView点击按钮后动画无法重启问题求助

解决UIProgressView首次点击正常,后续动画无法重启的问题

嘿,我看了你的代码,问题主要出在动画的异步执行顺序和未正确管理定时器这两个点上,咱们一步步来解决:

问题根源分析

  1. 重置动画与启动动画的冲突:你调用resetProgress()时用了animated: true,这个动画是异步的——函数执行完返回后,进度条还在慢慢往0走。这时候你立刻调用startProgressView去把进度拉到1,系统会把这两个动画合并,结果就是你看不到重置后的动画效果,直接跳转到新的动画状态。
  2. 多定时器冲突:每次点击按钮都会创建一个新的Timer,之前的定时器如果没被销毁,会继续在后台运行,不仅浪费资源,还可能干扰进度条的状态逻辑。
  3. 双重动画嵌套:在UIView.animate闭包里调用progressView.setProgress(1.0, animated: true),等于同时触发了UIView的帧动画和progressView自身的进度动画,两者叠加会导致动画异常。

修复后的完整代码

import UIKit

class ViewController: UIViewController {
    let eggTimes = ["Soft" : 5, "Medium" : 7, "Hard": 12]
    @IBOutlet weak var progressView: UIProgressView!
    // 新增属性保存当前定时器,方便管理
    var currentTimer: Timer?
    
    // 重置进度条:取消所有动画,立刻回到0
    func resetProgress(){
        progressView.layer.removeAllAnimations()
        progressView.setProgress(0, animated: false)
        print("function progress view reset fired")
    }
    
    // 启动进度条动画:用UIView的动画统一控制,避免双重动画
    func startProgressView(duration: Double) {
        progressView.layer.removeAllAnimations()
        UIView.animate(withDuration: duration) {
            print("progress bar animation started")
            self.progressView.setProgress(1.0, animated: false)
        }
    }
    
    @IBAction func hardnessSelected(_ sender: UIButton) {
        // 第一步:先停止之前的定时器,避免多个定时器同时运行
        currentTimer?.invalidate()
        
        // 第二步:重置进度条
        resetProgress()
        print("progress bar has been reset")
        
        // 第三步:获取选中的硬度对应的时长
        let hardness = sender.currentTitle!
        let totalSeconds = Double(eggTimes[hardness]!) * 10
        print("total duration: \(totalSeconds) ")
        
        // 第四步:启动进度动画
        self.startProgressView(duration: totalSeconds)
        
        // 第五步:启动新的定时器
        var timerCounter = eggTimes[hardness]! * 10
        currentTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] timer in
            guard let self = self else {
                timer.invalidate()
                return
            }
            if timerCounter > 0 {
                timerCounter -= 1
            } else {
                print("egg ready")
                timer.invalidate()
                self.currentTimer = nil // 清空定时器引用
            }
        }
    }
}

关键修复点说明

  • 强制终止所有旧动画:每次重置或启动新动画前,调用progressView.layer.removeAllAnimations(),确保之前的动画完全停止,不会和新动画冲突。
  • 同步重置进度:重置进度条时用animated: false,让进度条立刻回到0,而不是等待异步动画完成,这样后续的新动画能从正确的起点开始。
  • 统一动画控制:在UIView.animate闭包里调用setProgress时用animated: false,让UIView的动画统一管理进度变化的过渡效果,避免双重动画导致的异常。
  • 定时器管理:用currentTimer属性保存当前定时器,每次点击先销毁旧定时器,再创建新的,避免多个定时器同时运行。
  • 弱引用避免内存泄漏:在Timer的闭包里用[weak self],防止ViewController被定时器强引用导致内存泄漏。

这样修改后,不管你点击多少次按钮,进度条都会先立刻重置为0,然后正常启动新的进度动画,定时器也不会出现多个同时运行的问题啦~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 11:34:08