在 UICollectionView 中删除单元格后,如何更新作为 UICollectionViewCell 一部分的按钮标签?

Posted

技术标签:

【中文标题】在 UICollectionView 中删除单元格后,如何更新作为 UICollectionViewCell 一部分的按钮标签?【英文标题】:How to update the button tag which is part of UICollectionViewCell after a cell is deleted in UICollectionView? 【发布时间】:2016-03-04 13:02:05 【问题描述】:

这是一个困扰我很久的问题。 这是代码

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 = "\u20B9 " + (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

【问题讨论】:

删除单元格时只更新您的收藏视图 可以写你单元格的删除代码,这样我可以更好的回答你 我正在用self.collectionViewLove.reloadData()更新它 你能不能为 cellForItemAtIndexPath 写代码 @MalavSoni 给你 【参考方案1】:

有几点:

    您在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 = "\u20B9 " + (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)

【讨论】:

【参考方案2】:

除非需要显示单元格,否则将数据存储在单元格中可能不是一个好主意。相反,您可以依靠UICollectionView 为您提供正确的indexPath,然后使用它从您的数据源中删除并更新collectionview。 为此,请使用带有单元格的委托模式。

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,该 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
    

【讨论】:

【参考方案3】:

我遇到了类似的问题,我通过在完成块中重新加载集合视图找到了答案。

只需像这样更新您的代码。

let indexPath = NSIndexPath(forRow: sender.tag, inSection: 0)

collectionViewLove?.performBatchUpdates(
    self.collectionViewLove?.deleteItemsAtIndexPaths([indexPath])
    self.wishlist?.results.removeAtIndex(indexPath.row)
, completion: 
    self.collectionViewLove?.reloadData()
)

Nik 在UICollectionView Performing Updates using performBatchUpdates 中提到过

【讨论】:

以上是关于在 UICollectionView 中删除单元格后,如何更新作为 UICollectionViewCell 一部分的按钮标签?的主要内容,如果未能解决你的问题,请参考以下文章

UICollectionView:删除单元格问题

UICollectionView 单元格删除

如何删除 UICollectionView 中单元格之间的空间? [复制]

如何在 UICollectionView 拖放期间删除“幽灵”单元格,并使移动单元格不透明?

UICollectionView 删除选定的单元格

如何从 UICollectionView 中正确删除单元格?