这是一个我已经坚持了很长一段时间的问题。 这是代码
let indexPath = NSIndexPath(forRow: sender.tag, inSection: 0)
collectionViewLove?.performBatchUpdates({() -> Void in
self.collectionViewLove?.deleteItemsAtIndexPaths([indexPath])
self.wishlist?.results.removeAtIndex(indexPath.row)
self.collectionViewLove?.reloadData()}, completion: nil)}
我在每个UICollectionViewCell
内都有一个按钮,可以在点击时将其删除。我检索indexPath
的唯一方法是通过按钮标记。我在
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
但是每次删除时,第一次删除相应的单元格,而下次删除单击后单击的单元格。原因是当我调用函数reloadData()
时,我的按钮标记没有得到更新。
理想情况下,当我拨打reloadData()
时,
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
应该调用并更新每个单元格的按钮标记。但那并没有发生。解决任何人?
编辑:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
collectionView.registerNib(UINib(nibName: "LoveListCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "Cell")
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! LoveListCollectionViewCell
cell.imgView.hnk_setImageFromURL(NSURL(string: (wishlist?.results[indexPath.row].image)!)!, placeholder: UIImage(named: "preloader"))
let item = self.wishlist?.results[indexPath.row]
cell.layer.borderColor = UIColor.grayColor().CGColor
cell.layer.borderWidth = 1
cell.itemName.text = item?.title
cell.itemName.numberOfLines = 1
if(item?.price != nil){
cell.price.text = "\u{20B9} " + (item?.price.stringByReplacingOccurrencesOfString("Rs.", withString: ""))!
}
cell.price.adjustsFontSizeToFitWidth = true
cell.deleteButton.tag = indexPath.row
cell.deleteButton.addTarget(self, action: "removeFromLoveList:", forControlEvents: .TouchUpInside)
cell.buyButton.tag = indexPath.row
cell.buyButton.backgroundColor = UIColor.blackColor()
cell.buyButton.addTarget(self, action: "buyAction:", forControlEvents: .TouchUpInside)
return cell
}
答案 0 :(得分:3)
有几件事:
您在cellForItemAtIndexPath
做了太多工作 - 您真的希望尽可能快地完成工作。例如,您只需要为collectionView注册一次nib - viewDidLoad()
是一个很好的地方。此外,您应该在单元格的prepareForReuse()
方法中设置单元格的初始状态,然后仅使用cellForItemAtIndexPath
更新项目中的自定义状态。
在删除完成之前,您不应重新加载数据。将reloadData
移动到完成块中,以便删除方法完成,并且视图有时间更新其索引。
但是,如果您不必首先拨打reloadData
,那会更好。您的实现将按钮的标记绑定到indexPath,但这些标记在不同的时间发生变异。把按钮的标签绑在比如愿望清单项ID上怎么样?然后,您可以根据ID查找相应的indexPath。
修改后的代码看起来像这样(未经测试但未经过语法检查):
// In LoveListCollectionViewCell
override func prepareForReuse() {
// You could also set these in the cell's initializer if they're not going to change
cell.layer.borderColor = UIColor.grayColor().CGColor
cell.layer.borderWidth = 1
cell.itemName.numberOfLines = 1
cell.price.adjustsFontSizeToFitWidth = true
cell.buyButton.backgroundColor = UIColor.blackColor()
}
// In your UICollectionView class
// Cache placeholder image since it doesn't change
private let placeholderImage = UIImage(named: "preloader")
override func viewDidLoad() {
super.viewDidLoad()
collectionView.registerNib(UINib(nibName: "LoveListCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "Cell")
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! LoveListCollectionViewCell
cell.imgView.hnk_setImageFromURL(NSURL(string: (wishlist?.results[indexPath.row].image)!)!, placeholder: placeholderImage)
let item = self.wishlist?.results[indexPath.row]
cell.itemName.text = item?.title
if(item?.price != nil){
cell.price.text = "\u{20B9} " + (item?.price.stringByReplacingOccurrencesOfString("Rs.", withString: ""))!
}
cell.deleteButton.tag = item?.id
cell.deleteButton.addTarget(self, action: "removeFromLoveList:", forControlEvents: .TouchUpInside)
cell.buyButton.tag = item?.id
cell.buyButton.addTarget(self, action: "buyAction:", forControlEvents: .TouchUpInside)
return cell
}
func removeFromLoveList(sender: AnyObject?) {
let id = sender.tag
let index = wishlist?.results.indexOf { $0.id == id }
let indexPath = NSIndexPath(forRow: index, inSection: 0)
collectionViewLove?.deleteItemsAtIndexPaths([indexPath])
wishlist?.results.removeAtIndex(index)
}
答案 1 :(得分:2)
除非需要显示单元格,否则将数据存储在单元格中可能不是一个好主意。相反,您可以依靠UICollectionView
为您提供正确的indexPath
,然后将其用于从数据源中删除并更新集合视图。
为此,请使用带有单元格的委托模式。
1.定义控制器/数据源应符合的协议。
protocol DeleteButtonProtocol {
func deleteButtonTappedFromCell(cell: UICollectionViewCell) -> Void
}
2.将一个委托属性添加到您的自定义单元格,该单元格将在删除操作上回调控制器。重要的是将单元格作为self
传递给该调用。
class CustomCell: UICollectionViewCell {
var deleteButtonDelegate: DeleteButtonProtocol!
// Other cell configuration
func buttonTapped(sender: UIButton){
self.deleteButtonDelegate.deleteButtonTappedFromCell(self)
}
}
3.然后在控制器中执行协议功能来处理删除操作。在这里,您可以从collectionView获取项目的indexPath,它可以用于删除数据并从collectionView中删除单元格。
class CollectionViewController: UICollectionViewController, DeleteButtonProtocol {
// Other CollectionView Stuff
func deleteButtonTappedFromCell(cell: UICollectionViewCell) {
let deleteIndexPath = self.collectionView!.indexPathForCell(cell)!
self.wishList.removeAtIndex(deleteIndexPath.row)
self.collectionView?.performBatchUpdates({ () -> Void in
self.collectionView?.deleteItemsAtIndexPaths([deleteIndexPath])
}, completion: nil)
}
}
4.确保在配置时为单元设置委托,以便委托回调某个地方。
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
//Other cell configuring here
var cell = collectionView.dequeueReusableCellWithReuseIdentifier("identifier", forIndexPath: indexPath)
(cell as! CustomCell).deleteButtonDelegate = self
return cell
}
}
答案 2 :(得分:1)
我遇到了类似的问题,我通过在完成块中重新加载集合视图找到答案。
只需更新您的代码即可。
let indexPath = NSIndexPath(forRow: sender.tag, inSection: 0)
collectionViewLove?.performBatchUpdates({
self.collectionViewLove?.deleteItemsAtIndexPaths([indexPath])
self.wishlist?.results.removeAtIndex(indexPath.row)
}, completion: {
self.collectionViewLove?.reloadData()
})
在UICollectionView Performing Updates using performBatchUpdates中由Nik提及