从收集视图部分删除n个项目可防止最后一个项目被重新加载在同一批次中
编辑:进一步测试后,这不是在iOS 15.2上执行更新,而是在iOS 13.0和14.0上进行更新,因此这似乎是iOS错误!
我正在尝试将批处理更新应用于uicollectionView
,但我发现,在删除的部分中,每个n
项目都被删除n
项目在本节的末尾将忽略任何重新加载。
我有一个示例uicollectionView
:
import UIKit
final class CollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
var data: [[String]] = []
var requestedIndexPaths: [IndexPath] = []
override func viewDidLoad() {
super.viewDidLoad()
collectionView.backgroundColor = .systemBackground
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "UICollectionViewCell")
applyInitialData(
[
["0, 0", "0, 1", "0, 2", "0, 3", "0, 4", "0, 5", "0, 6", "0, 7"],
]
)
let refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action: #selector(reloadAll), for: .valueChanged)
collectionView.refreshControl = refreshControl
}
@objc
private func reloadAll() {
collectionView.reloadData()
collectionView.refreshControl?.endRefreshing()
}
func applyInitialData(_ data: [[String]]) {
self.data = data
loadViewIfNeeded()
collectionView.reloadData()
collectionView.layoutIfNeeded()
requestedIndexPaths = []
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
requestedIndexPaths.append(indexPath)
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "UICollectionViewCell", for: indexPath)
cell.contentView.subviews.forEach { $0.removeFromSuperview() }
let label = UILabel()
label.text = data[indexPath.section][indexPath.row]
cell.contentView.addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
label.topAnchor.constraint(equalTo: cell.topAnchor),
label.leadingAnchor.constraint(equalTo: cell.leadingAnchor),
])
return cell
}
override func numberOfSections(in collectionView: UICollectionView) -> Int {
data.count
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
data[section].count
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.frame.size.width, height: 40)
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt: IndexPath) {
updateUsingReload()
// updateUsingInsertAndDelete()
}
/// With this method 0, 6 will not be updated until pull-to-refresh is used.
private func updateUsingReload() {
collectionView.performBatchUpdates({
data[0][0] = "0, 0 (updated)"
data[0][1] = "0, 1 (updated)"
data[0][4] = "0, 4 (updated)"
data[0][5] = "0, 5 (updated)"
data[0][6] = "0, 6 (updated)"
data[0].remove(at: 3)
data[0].remove(at: 2)
collectionView.deleteItems(at: [
IndexPath(item: 2, section: 0),
IndexPath(item: 3, section: 0),
])
collectionView.reloadItems(at: [
IndexPath(item: 0, section: 0),
IndexPath(item: 1, section: 0),
IndexPath(item: 4, section: 0),
IndexPath(item: 5, section: 0),
IndexPath(item: 6, section: 0),
])
})
}
/// With this method all cells will be reloaded, but the animation is not as
/// nice because the cells are not really removed.
private func updateUsingInsertAndDelete() {
collectionView.performBatchUpdates({
data[0][0] = "0, 0 (updated)"
data[0][1] = "0, 1 (updated)"
data[0][4] = "0, 4 (updated)"
data[0][5] = "0, 5 (updated)"
data[0][6] = "0, 6 (updated)"
data[0].remove(at: 3)
data[0].remove(at: 2)
collectionView.deleteItems(at: [
IndexPath(item: 2, section: 0),
IndexPath(item: 3, section: 0),
IndexPath(item: 4, section: 0),
IndexPath(item: 5, section: 0),
IndexPath(item: 6, section: 0),
])
collectionView.insertItems(at: [
// 2 items have really been deleted, these item use the "after"
// indexes and are 4, 5, and 6 prior to the update.
IndexPath(item: 2, section: 0),
IndexPath(item: 3, section: 0),
IndexPath(item: 4, section: 0),
])
collectionView.reloadItems(at: [
IndexPath(item: 0, section: 0),
IndexPath(item: 1, section: 0),
])
})
}
}
当我点击一个单元格(触发更新)时,0,6
单元格不会更新。使用UpdateSertInSertAndDelete
函数的功能确实重新加载了所有单元格,但是没有删除动画,例如使用Update> UpdateRusingReload
。
我在一个完整的项目中有一个示例,网址为 https://github.com/josephub.com/josephduffy/collectionviewTeviewTestEttestingTestinging 。
Edit: Upon further testing this is not performing the update on iOS 15.2, but does update on iOS 13.0 and 14.0, so this appears to be an iOS bug!
I'm trying to apply batch updates to a UICollectionView
but I'm finding that for every N
items in a section that are deleted N
items at the end of the section will ignore any reloads.
I have an example UICollectionView
:
import UIKit
final class CollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
var data: [[String]] = []
var requestedIndexPaths: [IndexPath] = []
override func viewDidLoad() {
super.viewDidLoad()
collectionView.backgroundColor = .systemBackground
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "UICollectionViewCell")
applyInitialData(
[
["0, 0", "0, 1", "0, 2", "0, 3", "0, 4", "0, 5", "0, 6", "0, 7"],
]
)
let refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action: #selector(reloadAll), for: .valueChanged)
collectionView.refreshControl = refreshControl
}
@objc
private func reloadAll() {
collectionView.reloadData()
collectionView.refreshControl?.endRefreshing()
}
func applyInitialData(_ data: [[String]]) {
self.data = data
loadViewIfNeeded()
collectionView.reloadData()
collectionView.layoutIfNeeded()
requestedIndexPaths = []
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
requestedIndexPaths.append(indexPath)
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "UICollectionViewCell", for: indexPath)
cell.contentView.subviews.forEach { $0.removeFromSuperview() }
let label = UILabel()
label.text = data[indexPath.section][indexPath.row]
cell.contentView.addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
label.topAnchor.constraint(equalTo: cell.topAnchor),
label.leadingAnchor.constraint(equalTo: cell.leadingAnchor),
])
return cell
}
override func numberOfSections(in collectionView: UICollectionView) -> Int {
data.count
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
data[section].count
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.frame.size.width, height: 40)
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt: IndexPath) {
updateUsingReload()
// updateUsingInsertAndDelete()
}
/// With this method 0, 6 will not be updated until pull-to-refresh is used.
private func updateUsingReload() {
collectionView.performBatchUpdates({
data[0][0] = "0, 0 (updated)"
data[0][1] = "0, 1 (updated)"
data[0][4] = "0, 4 (updated)"
data[0][5] = "0, 5 (updated)"
data[0][6] = "0, 6 (updated)"
data[0].remove(at: 3)
data[0].remove(at: 2)
collectionView.deleteItems(at: [
IndexPath(item: 2, section: 0),
IndexPath(item: 3, section: 0),
])
collectionView.reloadItems(at: [
IndexPath(item: 0, section: 0),
IndexPath(item: 1, section: 0),
IndexPath(item: 4, section: 0),
IndexPath(item: 5, section: 0),
IndexPath(item: 6, section: 0),
])
})
}
/// With this method all cells will be reloaded, but the animation is not as
/// nice because the cells are not really removed.
private func updateUsingInsertAndDelete() {
collectionView.performBatchUpdates({
data[0][0] = "0, 0 (updated)"
data[0][1] = "0, 1 (updated)"
data[0][4] = "0, 4 (updated)"
data[0][5] = "0, 5 (updated)"
data[0][6] = "0, 6 (updated)"
data[0].remove(at: 3)
data[0].remove(at: 2)
collectionView.deleteItems(at: [
IndexPath(item: 2, section: 0),
IndexPath(item: 3, section: 0),
IndexPath(item: 4, section: 0),
IndexPath(item: 5, section: 0),
IndexPath(item: 6, section: 0),
])
collectionView.insertItems(at: [
// 2 items have really been deleted, these item use the "after"
// indexes and are 4, 5, and 6 prior to the update.
IndexPath(item: 2, section: 0),
IndexPath(item: 3, section: 0),
IndexPath(item: 4, section: 0),
])
collectionView.reloadItems(at: [
IndexPath(item: 0, section: 0),
IndexPath(item: 1, section: 0),
])
})
}
}
When I tap a cell (to trigger the updates) the 0, 6
cell does not update. Using the updateUsingInsertAndDelete
function instead does reload all the cells, but there's no delete animation like there is when using updateUsingReload
.
I have this example in a full project at https://github.com/JosephDuffy/CollectionViewTesting.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您不能将重新启动(或重新配置)用于移动的重新加载项目。好像ReloAditems认为所讨论的项目在更新过程中保持其位置。看来没有办法同时进行动画和更新项目。
您可以在移动后更新项目,也可以尝试使用
CollectionView.cellforitem(at:)
来实现自定义单元动画You can't use reloadItems (or reconfigureItems) to reload items which was moved. Seems like reloadItems assume the items in question are keeping their positions during update. It looks like there is no way to animate and update item at the same time.
You can either update item after it was moved or try to implement custom cell animation using
collectionView.cellForItem(at:)