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

如何实现自定义UITableViewCell中progressBar的勾选触发动画效果?

Hey Matt, let's break down what's going wrong with both of your approaches and fix that progress bar animation!

First Approach: Why You Can't Access the Cell

The immediate issue here is that you've mixed up the section and row parameters when creating your IndexPath.

IndexPath(item:row, section:section) is the correct initializer, but you wrote:

IndexPath(item: indexSection!, section: indexRow!)

This points to a non-existent cell position, so tableView.cellForRow(at:) returns nil—hence the fatal error when you force-unwrap cell.

Even if you fixed this index mix-up, handling cell animations in the table view controller's delegate is not ideal. Cell-specific interactions should stay encapsulated within the cell itself to keep your code clean and avoid tight coupling.

Second Approach: Why the Animation Isn't Working

You're conflicting two animation systems here:

  • setProgress(_:animated:) triggers the UIProgressView's built-in animation (with a fixed short duration)
  • Wrapping this in UIView.animate tries to override that timing, which breaks the smooth transition and causes the sudden jump.

The fix is to skip the animated parameter entirely and directly modify the progress property inside a UIView.animate block. This gives you full control over the duration.

Corrected Code for TaskCell.swift

Here's how to adjust your checkbox action handler:

@IBAction func checkBoxAction(_ sender: Any) {
    // Toggle the checked state in your data model first
    let newCheckedState = !items![indexRow!].checked
    items![indexRow!].checked = newCheckedState
    
    // Notify the delegate of the state change
    delegate?.changeButton(
        state: newCheckedState, 
        indexSection: indexSection!, 
        indexRow: indexRow!, 
        itemID: itemID
    )
    
    // Animate the progress bar with your desired duration
    let targetProgress = newCheckedState ? 1.0 : 0.0
    let animationDuration = newCheckedState ? 5.0 : 1.0
    
    UIView.animate(withDuration: animationDuration) {
        self.progressBar.progress = targetProgress
    }
}

Bonus: Improve Code Robustness

Storing items, indexSection, and indexRow directly in the cell is risky—these values can become invalid when cells are reused or the table view refreshes. A better pattern is to pass a task model directly to the cell:

// Inside TaskCell.swift
class TaskCell: UITableViewCell {
    var taskItem: TaskItem! {
        didSet {
            // Configure initial state when the model is set
            progressBar.progress = taskItem.checked ? 1.0 : 0.0
            // Update your checkbox state here too
        }
    }
    
    @IBAction func checkBoxAction(_ sender: Any) {
        taskItem.checked = !taskItem.checked
        delegate?.changeButton(state: taskItem.checked, itemID: taskItem.id)
        
        let targetProgress = taskItem.checked ? 1.0 : 0.0
        let animationDuration = taskItem.checked ? 5.0 : 1.0
        
        UIView.animate(withDuration: animationDuration) {
            self.progressBar.progress = targetProgress
        }
    }
}

Then in your table view controller's cellForRowAt method, just set cell.taskItem = yourTaskModel—this eliminates forced unwraps and makes your code more maintainable.

内容的提问来源于stack exchange,提问作者M. Tol

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 20:57:34