UICollectionView拖拽后标签重复显示IndexPath问题求助
问题
我在使用两个UICollectionView,第一个包含带ID、图片的数据,第二个用于添加第一个中的单元格并支持拖拽操作。第二个UICollectionView的单元格内有一个标签,通过indexPath.item+1来显示添加数据的序号,但拖拽单元格后标签会出现序号重复的问题,请问该如何解决?
原代码
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { if collectionView == stretchAddedCV{ return addRoutine.count } else { return self.arrRoutine.count } } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { if collectionView == stretchAddedCV{ let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "AddedRoutineCell", for: indexPath) as! AddedRoutineCell let obj = self.addRoutine[indexPath.item] if let img = obj.thumbnail{ if let imgUrl = URL.init(string: img) { cell.img.kf.setImage(with: imgUrl, placeholder: PlaceHolderImage) } } let count = indexPath.item + 1 cell.lblNo.text = "\(count)" // if addImage.indices.contains(indexPath.item) { // let imageUrl = addImage[indexPath.item] // cell.img.kf.setImage(with: URL(string: imageUrl), placeholder: PlaceHolderImage) // } return cell } else{ let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "RoutineListCell", for: indexPath) as! RoutineListCell let obj = arrRoutine[indexPath.item] cell.configure(with: obj) if let title = obj.title { cell.lblTitle.text = title } if let url = obj.thumbnail { if let imgUrl = URL.init(string: url) { cell.img.kf.setImage(with: imgUrl, placeholder: PlaceHolderImage) } } // cell.contentView.alpha = 1.0 // cell.isUserInteractionEnabled = !obj.isDisable return cell } } // drag and Drope Mothed func collectionView(_ UICollectionView: UICollectionView, canMoveItemAt indexPath: IndexPath) -> Bool { return true } func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) { guard destinationIndexPath.item < addRoutine.count else { return } let temp = self.addRoutine.remove(at: sourceIndexPath.item) self.addRoutine.insert(temp, at: destinationIndexPath.item) self.stretchAddedCV.reloadItems(at: [destinationIndexPath, sourceIndexPath]) } //drag and Drope Longe press @objc func handleLongGesture(gesture: UILongPressGestureRecognizer) { switch gesture.state { case .began: guard let selectedIndexPath = self.stretchAddedCV.indexPathForItem(at: gesture.location(in: self.stretchAddedCV)) else { break } self.stretchAddedCV.beginInteractiveMovementForItem(at: selectedIndexPath) case .changed: self.stretchAddedCV.updateInteractiveMovementTargetPosition(gesture.location(in: gesture.view!)) case .ended: self.stretchAddedCV.endInteractiveMovement() default: self.stretchAddedCV.cancelInteractiveMovement() } }
解决方案
问题根源是拖拽后你只刷新了源位置和目标位置的单元格,但所有单元格的序号都因位置变动而改变了,未刷新的单元格会保留旧序号,导致重复。
修复方法
替换拖拽方法中的刷新逻辑,有两种可选方案:
方案1:直接刷新整个列表(简单可靠)
func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) { guard destinationIndexPath.item < addRoutine.count else { return } let temp = self.addRoutine.remove(at: sourceIndexPath.item) self.addRoutine.insert(temp, at: destinationIndexPath.item) // 替换原来的reloadItems,刷新整个CollectionView self.stretchAddedCV.reloadData() }
方案2:仅刷新可见单元格(性能更优)
如果列表数据量大,不想全量刷新,可以只更新当前可见的单元格:
func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) { guard destinationIndexPath.item < addRoutine.count else { return } let temp = self.addRoutine.remove(at: sourceIndexPath.item) self.addRoutine.insert(temp, at: destinationIndexPath.item) // 遍历所有可见单元格,更新序号标签 guard let visibleCells = stretchAddedCV.visibleCells as? [AddedRoutineCell] else { return } for cell in visibleCells { if let indexPath = stretchAddedCV.indexPath(for: cell) { cell.lblNo.text = "\(indexPath.item + 1)" } } }
说明
- 方案1的
reloadData()会让所有单元格重新走cellForItemAt方法,确保序号完全正确,适合数据量不大的场景。 - 方案2只更新可见单元格,避免了不必要的刷新,适合数据量较大、追求流畅性的场景。
内容的提问来源于stack exchange,提问作者Payal Bhatt
相关产品推荐
相关产品推荐

