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

UICollectionView点击删除动画异常 滚动后cell错位偏移问题

UICollectionView删除动画导致未点击cell偏移问题原因

核心触发原因

问题的根源是你直接修改cell子视图的位置属性,却没有在cell复用链路里做状态重置,和UICollectionView的cell复用机制直接相关:

  • 你的删除逻辑里,直接通过cellForItem(at:)获取当前点击的cell,修改cell内部image视图的center.x做平移动画,这个修改是持久生效在对应cell实例上的,不会自动还原。
  • 当动画执行完成、你调用deleteItems移除对应cell后,这个被改了image位置的cell会被回收进入UICollectionView的复用池,等待下一次被取出展示新位置的内容。
  • 当你向下滚动列表时,系统会从复用池取出闲置cell填充新出现在可视区域的位置,如果你没有在cellForItemAt:indexPath数据源方法、或者cell自身的prepareForReuse方法里把image的center重置为默认初始值,被复用的cell就会带着之前右移300的偏移量展示出来,看起来就像没被点击的cell凭空跑了位置,和你描述的「动画执行了但没触发完成回调」的表现完全一致。
  • 连续删除1-3个cell时没出问题,只是因为这时候被修改过属性的cell还没被复用到其他位置,属于场景巧合,不是逻辑真的没问题。

额外隐藏隐患

你当前的代码还有个会导致偶现异常的问题:

  • 动画闭包里是通过可选绑定取cell的,如果动画执行的0.5秒过程中用户快速滑动列表,把被点击的cell滑出了可视区域,collectionView.cellForItem(at:)会返回nil,这时候平移动画不会执行,但完成闭包里你还是会直接删除数据源和对应item,轻则出现UI和数据不同步,重则触发数组越界崩溃。

问题对应核心代码

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        UIView.animate(withDuration: 0.5) {
            if let cell = collectionView.cellForItem(at: indexPath) as? CollectionViewCell {
                cell.image.center.x += 300 }
        } completion: { _ in
            ImageModel.images.remove(at: indexPath.row)
            collectionView.deleteItems(at: [indexPath])
        }
    }

修复思路:要么在cell的prepareForReuse方法里把image的frame/center重置为默认值,要么不要直接改cell子视图的位置,用transform做动画,动画结束后把transform还原为.identity再删除cell,从根源避免脏状态被带进复用流程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 10:07:04