javimuu
javimuu

Reputation: 1859

UICollectionView - How to update all cells with change from one cell

I have a CollectionView and inside each cell of this collectionView there is one textField.

If all content of the textfield is nil, when I change content of one textfield (for example cell_1) all other textfields will auto update content with value like the content of textfield in cell_1.

I have tried with collectionView.visibleCells but it does not work properly for my scene.

Is there any way that I can change one cell then update for all cells in CollectionView?

Please help. Thanks in advance!

Upvotes: 0

Views: 4265

Answers (2)

Paul Peelen
Paul Peelen

Reputation: 10329

Clear new cells:
Since I am not understanding your question to a 100%, I assume that your problem is that new cells get the value of cell_1, which is not something you want.

If that is the case, then there is a function called prepareForReuse in UICollectionViewCell. In your subclass of the UICollectionViewCell, implement the following:

override func prepareForReuse() {
    super.prepareForReuse()
    textfield.text = ""
}

That should do the trick, given that your textfield is called textfield.

Performs any clean up necessary to prepare the view for use again. https://developer.apple.com/reference/uikit/uicollectionreusableview/1620141-prepareforreuse

Update all cells:
If your question is how to update other cells to get the same content as cell_1, then this means that the Collection View subclass needs to know about an update in cell_1 and then transform that update to the other cells. One way of doing that is having your textfields delegate set in the Collection View. When the value is changed (textField(_:shouldChangeCharactersIn:replacementString:)), get all the visible cells and update those textfields accordingly. Maybe also save either a reference to the textfield in cell_1, or a string variable in your Collection View stating the latest entered value so you can update cells as they get rendered. You don't want to use reloadData() though, since that will remove the focus from the textField, since the textField is reloaded.

Solution:

class ViewController: UIViewController {
    @IBOutlet weak var collectionView: UICollectionView!

    fileprivate var customString: String?
}

extension ViewController: UICollectionViewDataSource {

    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 5
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCell", for: indexPath) as! CustomCell

        cell.textField.delegate = self
        cell.textField.text = customString

        return cell
    }

}

extension ViewController: UITextFieldDelegate {

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

        customString = string

        for cell in collectionView.visibleCells {
            if let cell = cell as? CustomCell,
                let text = textField.text,
                cell.textField != textField {
                cell.textField.text = text+string
            }
        }

        return true
    }

}

The only con in the code above is that it loops through cells that currently are visible. Usually I'd recommend to stay out of looping unless absolutely necessary, but the alternative to the solution above would be to post a notification and having the cells listen to that notification and update its content accordingly. Doing that would not only be overkill, but also something notifications aren't really meant for. Third option would be to hold a weak reference in an array to every textfield, which might not be optimal as well since it creates unnecessary overhead. After all visibleCells already is an array of the cells currently visible which each hold a reference to an UITextField.

Upvotes: 2

Prema Janoti
Prema Janoti

Reputation: 856

try this -

Step 1 -

Create a variable like and IBOutlet of your collection view -

var xyzString: String?
@IBOutlet weak var collectionView: UICollectionView! // IBOutlet of your collection view

Step 2 -

  func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TagViewCell", for: indexPath) as? TagViewCell // instead of TagViewCell give your custom cell class name
    if self.xyzString != nil {
      cell?.txtField.text = self.xyzString // if you want same value for all cell
     }
    return cell!
}

Step 3 -

  func textFieldDidEndEditing(_ textField: UITextField) {
    self.xyzString = textField.text
    self.collectionView.reloadData()
}

Upvotes: 1

Related Questions