Dhinakaran
Dhinakaran

Reputation: 125

Update label inside UICollectionView

I have created this using UICollectionView When I click the Add(+) or Remove(-) button then I want to update the label. How can I achieve this?

MainViewController.swift

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    if(collectionView == ProductCollectionView){
        let Productcell = self.ProductCollectionView.dequeueReusableCell(withReuseIdentifier:"ProductCollectionViewCell", for: indexPath) as! ProductCollectionViewCell

        Productcell.AddOrMinusLabel.text = "\(bestOfferProductCount[indexPath.row])"
        Productcell.ProdName.text = bestOfferProductName[indexPath.row]
        Productcell.ProdPrice.text = bestOfferProductPrice[indexPath.row]
        Productcell.ProdtOrgPrice.text = bestOfferProductOriginalPrice[indexPath.row]
        Productcell.ProdWeight.text = bestOfferProductWeight[indexPath.row]+" "+bestOfferProductUnit[indexPath.row]
        Productcell.ProductImage.setImageFromURl(stringImageUrl: bestOfferProductImage[indexPath.row])

        return Productcell
    }

}

ProductCollectionViewCell.swift

import UIKit

class ProductCollectionViewCell: UICollectionViewCell {

@IBOutlet weak var ProdPrice: UILabel!
@IBOutlet weak var ProdtOrgPrice: UILabel!
@IBOutlet weak var ProductImage: UIImageView!
@IBOutlet weak var ProdName: UILabel!
@IBOutlet weak var ProdWeight: UILabel!

}

Upvotes: 2

Views: 2496

Answers (4)

iOS Developer
iOS Developer

Reputation: 558

I would do this using protocols, Add this to your cell's class and add the IBAction's to UIButton.

class ProductCollectionViewCell: UICollectionViewCell {

  @IBOutlet weak var ProdPrice: UILabel!
  @IBOutlet weak var ProdtOrgPrice: UILabel!
  @IBOutlet weak var ProductImage: UIImageView!
  @IBOutlet weak var ProdName: UILabel!
  @IBOutlet weak var ProdWeight: UILabel!

  weak open var delegate: ProductCollectionViewCellDelegate?

  @IBAction func btnIncrement(_ sender: UIButton)
  {
    if let d = self.delegate {
      d.didTapOnIncrement(cell: self)
    }
  }

  @IBAction func btnDecrement(_ sender: UIButton)
  {
    if let d = self.delegate {
      d.didTapOnDecrement(cell: self)
    }
  }
}

protocol ProductCollectionViewCellDelegate: NSObjectProtocol {
    func didTapOnIncrement(cell: ProductCollectionViewCell)
    func didTapOnDecrement(cell: ProductCollectionViewCell)
}

Now in you cellForItemAt method, add this line -\

cell.delegate = self

Now confirm that delegate confirms the protocols. In this example, I suppose it is your viewController.

extension ViewController: ProductCollectionViewCellDelegate {

  func didTapOnIncrement(cell: ProductCollectionViewCell) {
    //let indexPath = self.tableView.indexPath(for: cell)
    //You have the cell's instance here. You can also get the indexPath by delegate method.
    //You can add the increment-decrement logic here.
  }

  func didTapOnDecrement(cell: ProductCollectionViewCell) {
    //let indexPath = self.tableView.indexPath(for: cell)
    //You have the cell's instance here. You can also get the indexPath by delegate method.
    //You can add the increment-decrement logic here.
  }

}

Upvotes: 2

Pratik Prajapati
Pratik Prajapati

Reputation: 1105

Try this simple n sober

add this code in your viewcontroller

@IBAction func onBtnPlusClick(_ sender : UIButton) {
    if let cell = sender.superview?.superview as? ProductCollectionViewCell {
        let indexPath = yourCollectionViewOutlet.indexPath(for: cell)
    //Do whatever you want or update your data model values
         yourCollectionViewOutlet.reloadData()
    }
}

@IBAction func onBtnMinusClick(_ sender : UIButton) {
        if let cell = sender.superview?.superview as? ProductCollectionViewCell {
            let indexPath = yourCollectionViewOutlet.indexPath(for: cell)
        //Do whatever you want or update your data model values
         yourCollectionViewOutlet.reloadData()
        }
    }

In your cellForItemAt add target to button

btnPlus.addTarget(self, action: #selector(self. onBtnPlusClick(_:)), for: .touchUpInside) 
btnMinus.addTarget(self, action: #selector(self. onBtnPlusClick(_:)), for: .touchUpInside) 

Add two button outlets in ProductCollectionViewCell class

@IBOutlet var btnPlus : UIButton!
@IBOutlet var btnMinus : UIButton!

That's it, hope this help

Upvotes: 0

Ashwin Shrestha
Ashwin Shrestha

Reputation: 528

i say, always configure your cell data inside the cell class

import UIKit

class ProductCollectionViewCell: UICollectionViewCell {
@IBOutlet weak var addOrMinusLabel: UILabel!
@IBOutlet weak var ProdPrice: UILabel!
@IBOutlet weak var ProdtOrgPrice: UILabel!
@IBOutlet weak var ProductImage: UIImageView!
@IBOutlet weak var ProdName: UILabel!
@IBOutlet weak var ProdWeight: UILabel!

var count = 1 {
    didSet{
        self.addOrMinusLabel.text = "\(count)"
    }
}


 func configureData(count: Int) {
    self.count = count
}

@IBAction func subtract(_ sender: UIButton) {
    self.count -= 1

}
@IBAction func add(_ sender: UIButton) {
    self.count += 1
}

}

and in your view controller

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

if(collectionView == ProductCollectionView){
    let Productcell = self.ProductCollectionView.dequeueReusableCell(withReuseIdentifier:"ProductCollectionViewCell", for: indexPath) as! ProductCollectionViewCell
    Productcell.configureData(count: (bestOfferProductCount[indexPath.row]))

   // do try to configure these below labels also within cell class 
    Productcell.ProdName.text = bestOfferProductName[indexPath.row]
    Productcell.ProdPrice.text = bestOfferProductPrice[indexPath.row]
    Productcell.ProdtOrgPrice.text = bestOfferProductOriginalPrice[indexPath.row]
    Productcell.ProdWeight.text = bestOfferProductWeight[indexPath.row]+" "+bestOfferProductUnit[indexPath.row]
    Productcell.ProductImage.setImageFromURl(stringImageUrl: bestOfferProductImage[indexPath.row])

    return Productcell
}

}

Upvotes: 2

farzadshbfn
farzadshbfn

Reputation: 2748

There are multiple ways to approach this.

1. Old Delegate mechanism

When you're dequeuing a Cell, you have to removeAllObservers, then AddTarget from cell to your ViewController for tapEvents of Plus and Minus sign with sender. In your callee method, you have to fetch it's superView (until you reach the collectionViewCell view) and then ask from UICollectoinView for itemIndex for that cell, and update your view and cell and model accordingly.

2. Using Closures

You can define two closures one for plus and one for minus in your Cell and instead of adding Target to your viewController, add targets to your cell and call corresponding closures and each time you're trying to return a Cell, set those closures and act on them accordingly.

class CustomCell: UICollectionCell {
    var plusAction: (() -> Void)?
    var minusAction: (() -> Void)?
    @IBOutlet var counterLabel: UILabel!

    @IBAction plusTapped() {
        plusAction?()
    }

    @IBAction minusTapped() {
        minusAction?()
    }
}

and in your cellDequeue method:

cellForItemAtIndexPath(/*...other parameters...*/) -> UICollectionCell {
    let cell = collectionView.dequeueCell(/*...other parameters...*/) as! CustomCell
    // other customizations
    // weak allocation in closure might not be needed here since closure reference is nullable on the other end, but i wrote it just in-case.
    cell.plusAction = { [weak weakCell = cell] in
        let counter = 0 // i said 0 for ex, You actually have to have them stored somewhere (even initial zeros) and fetch the actual value for this indexPath
        let newCounter = counter + 1
        // update your Model with newCounter
        weakCell?.counterLabel.text = "\(newCounter)"
    }

    cell.minusAction = { [weak weakCell = cell] in
        let counter = 0 // i said 0 for ex, You actually have to have them stored somewhere (even initial zeros) and fetch the actual value for this indexPath
        let newCounter = counter - 1
        // update your Model with newCounter
        weakCell?.counterLabel.text = "\(newCounter)"
    }
}

Upvotes: 1

Related Questions