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

如何让UITableViewCell首次显示时仅执行一次动画?

Fix: Animate UITableViewCell Only Once on First Display

Hey there! The problem with your current code is that tableView(_:willDisplay:forRowAt:) gets called every time a cell enters the screen—including when you scroll back up to cells that were already shown. That means your animation runs over and over again, which isn't what you want.

Here are a few clean ways to make the animation fire only once when the cell first appears:


Option 1: Add a Flag to Your Custom Cell (Most Straightforward)

If you're using a custom UITableViewCell subclass, just add a boolean property to track if the animation has already run:

class YourCustomCell: UITableViewCell {
    // Track if the animation has completed
    var hasAnimated = false
}

Then update your willDisplay method to check this flag before animating:

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    // Cast to your custom cell type and check the flag
    guard let customCell = cell as? YourCustomCell, !customCell.hasAnimated else {
        return
    }

    // Set initial hidden state
    customCell.alpha = 0
    let transform = CATransform3DTranslate(CATransform3DIdentity, 0, 200, 0)
    customCell.layer.transform = transform

    // Animate to visible state
    UIView.animate(
        withDuration: 0.5,
        delay: 0,
        usingSpringWithDamping: 1,
        initialSpringVelocity: 1,
        options: .curveEaseOut
    ) {
        customCell.alpha = 1
        customCell.layer.transform = CATransform3DIdentity // Reset to original transform
    } completion: { _ in
        // Mark the cell as animated once the animation finishes
        customCell.hasAnimated = true
    }
}

Option 2: Use Associated Objects (No Custom Cell Needed)

If you don't want to create a custom cell subclass, you can use Objective-C runtime associated objects to add a flag to any UITableViewCell:

import ObjectiveC

// Create a unique key for the associated object
private var hasAnimatedKey: UInt8 = 0

extension UITableViewCell {
    var hasAnimated: Bool {
        get {
            return objc_getAssociatedObject(self, &hasAnimatedKey) as? Bool ?? false
        }
        set {
            objc_setAssociatedObject(self, &hasAnimatedKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
}

Then use the same logic in willDisplay:

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    guard !cell.hasAnimated else { return }

    cell.alpha = 0
    let transform = CATransform3DTranslate(CATransform3DIdentity, 0, 200, 0)
    cell.layer.transform = transform

    UIView.animate(
        withDuration: 0.5,
        delay: 0,
        usingSpringWithDamping: 1,
        initialSpringVelocity: 1,
        options: .curveEaseOut
    ) {
        cell.alpha = 1
        cell.layer.transform = CATransform3DIdentity
    } completion: { _ in
        cell.hasAnimated = true
    }
}

Option 3: Track Animated IndexPaths

You can also maintain a set of IndexPaths that have already been animated. This works well if your data doesn't change often:

// Store index paths that have been animated
private var animatedIndexPaths = Set<IndexPath>()

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    guard !animatedIndexPaths.contains(indexPath) else { return }

    cell.alpha = 0
    let transform = CATransform3DTranslate(CATransform3DIdentity, 0, 200, 0)
    cell.layer.transform = transform

    UIView.animate(
        withDuration: 0.5,
        delay: 0,
        usingSpringWithDamping: 1,
        initialSpringVelocity: 1,
        options: .curveEaseOut
    ) {
        cell.alpha = 1
        cell.layer.transform = CATransform3DIdentity
    } completion: { _ in
        self.animatedIndexPaths.insert(indexPath)
    }
}

Note: If your table view data updates (e.g., you add/remove rows), you'll need to clear or update the animatedIndexPaths set to match the new data.


All these approaches ensure the animation runs only once per cell, even when scrolling back and forth. Pick the one that fits your project setup best!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 06:29:16