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

UICollectionView中performBatchUpdates动画:如何移除淡入淡出效果?

解决集合视图选中section后的动画需求

针对你需要的「选中section后其他section立即消失,目标section平滑滑到顶部」的需求,下面逐个回答你的问题并给出可行方案:

1. 让删除和移动动画顺序执行

系统默认的performBatchUpdates会把所有更新操作打包成一组动画同时执行,要拆分顺序的话,可以分两次执行更新,且第一次删除操作禁用动画:

// 先更新数据源为仅保留目标section
data = [targetSectionData]

// 第一步:立即删除多余section,关闭动画
UIView.performWithoutAnimation {
    coll.performBatchUpdates({
        coll.deleteSections(removeIndexPathSections)
    }, completion: nil)
}

// 第二步:触发目标section的滑动动画
// 注意:删除后目标section的索引已变为0,此时可以直接滚动到该section的顶部
coll.scrollToItem(at: IndexPath(item: 0, section: 0), at: .top, animated: true)

这里用scrollToItem代替moveSection,因为删除其他section后目标section已经处于索引0的位置,moveSection不会产生任何视觉变化,直接滚动更直观。

2. 分别设置两种动画的时长

系统的performBatchUpdates不支持单独为不同操作设置动画时长,所有批量更新共享同一套动画参数(时长、曲线)。要实现不同时长的效果,只能通过拆分操作+手动动画的方式模拟,无法直接通过系统API实现。

3. 其他可行方案

方案一:隐藏cell+手动滚动动画

这是对你临时方案的优化,减少复用问题的影响:

// 1. 立即隐藏不需要的section的所有cell
for section in removeIndexPathSections {
    let itemCount = coll.numberOfItems(inSection: section)
    for item in 0..<itemCount {
        coll.cellForItem(at: IndexPath(item: item, section: section))?.isHidden = true
    }
}

// 2. 计算目标section顶部的偏移量
let targetIndexPath = IndexPath(item: 0, section: indexPathOfTargetRow)
let targetRect = coll.layoutAttributesForItem(at: targetIndexPath)?.frame ?? .zero
let targetOffset = CGPoint(
    x: 0,
    y: targetRect.origin.y - coll.contentInset.top - coll.safeAreaInsets.top
)

// 3. 执行滑动动画(时长0.5秒)
UIView.animate(withDuration: 0.5) {
    coll.contentOffset = targetOffset
} completion: { _ in
    // 4. 动画结束后更新数据源并刷新,确保视图与数据一致
    self.data = [self.targetSectionData]
    self.coll.reloadData()
    completion()
}

注意:在cell的prepareForReuse中务必添加isHidden = false,避免复用后cell异常隐藏。

方案二:快照视图模拟动画(推荐,无复用问题)

通过生成目标cell的快照,模拟滑动动画,完全避开cell复用的麻烦:

// 1. 获取目标cell并生成快照
guard let targetCell = coll.cellForItem(at: IndexPath(item: 0, section: indexPathOfTargetRow)) else {
    completion()
    return
}
let snapshot = targetCell.snapshotView(afterScreenUpdates: true)!
snapshot.frame = coll.convert(targetCell.frame, to: coll.superview)
coll.superview?.addSubview(snapshot)

// 2. 隐藏所有cell,让其他section立即消失
for section in 0..<coll.numberOfSections {
    for item in 0..<coll.numberOfItems(inSection: section) {
        coll.cellForItem(at: IndexPath(item: item, section: section))?.isHidden = true
    }
}

// 3. 计算顶部目标位置
let targetFrame = CGRect(
    x: coll.contentInset.left + coll.safeAreaInsets.left,
    y: coll.contentInset.top + coll.safeAreaInsets.top,
    width: coll.bounds.width - coll.contentInset.left - coll.contentInset.right - coll.safeAreaInsets.left - coll.safeAreaInsets.right,
    height: targetCell.frame.height
)
let targetFrameInSuperview = coll.convert(targetFrame, to: coll.superview)

// 4. 执行滑动动画
UIView.animate(withDuration: 0.5) {
    snapshot.frame = targetFrameInSuperview
} completion: { _ in
    // 5. 更新数据源、刷新视图并移除快照
    self.data = [self.targetSectionData]
    self.coll.reloadData()
    snapshot.removeFromSuperview()
    completion()
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 07:54:51