iosswiftuicollectionviewcgrect

How to stop collection triggering code when scrolling back in to view swift


I'm pretty new so apologies if my title doesn't phrase things correctly. I've been hacking away and haven't been able to find an answer to this problem.

I have a horizontally scrolling collection. I'm trying to visually show poll results programatically adding CGRect to the relevant item in the collection based on voting data held in a Firestore array.

This is working, but the problem is when you scroll away (so the item in the collection is off screen) and then back, the code to draw the CGRects gets triggered again and more graphics get added to the view. Is there a way to delete these CGRects when the user scrolls an item collection off screen so when the user scrolls the item back into view, code is triggered again it doesn't create duplicates?

Here are a couple of screenshots showing first and second load

First loadSecond load

Here is my code (cell b is where the CGrect gets triggered)

//COLLECTION VIEW CODE    
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        if collectionView == self.sentCollectionView {
            let cellA = collectionView.dequeueReusableCell(withReuseIdentifier: "sCell", for: indexPath) as! SentCollectionViewCell
            
            cellA.sentQuestionLabel.text = sentMessages[indexPath.row].shoutText
            // Set up cell
            return cellA
        }
        else {
            let cellB = receivedCollectionView.dequeueReusableCell(withReuseIdentifier: "pCell", for: indexPath) as! ReceivedCollectionViewCell
            
            receivedMessages[indexPath.row].pollTotal = receivedMessages[indexPath.row].pollResults.reduce(0, +)
            print("Sum of Array is : ", receivedMessages[indexPath.row].pollTotal!)
            cellB.receivedShoutLabel.text = receivedMessages[indexPath.row].shoutText
            
            print(receivedMessages[indexPath.row].pollResults.count)
            
            if receivedMessages[indexPath.row].pollResults != [] {
                for i in 0...receivedMessages[indexPath.row].pollResults.count - 1 {
                    cellB.resultsView.addSubview(sq(pollSum: receivedMessages[indexPath.row].pollTotal!, pollResult: receivedMessages[indexPath.row].pollResults[i]))
                }
            }

            return cellB
        }
    }

//THIS DRAWS THE CGRECT
    func sq(pollSum: Int, pollResult: Int) -> UIView {
        // divide the width by total responses
        let screenDivisions = Int(view.frame.size.width) / pollSum

        // the rectangle top left point x axis position.
        let xPos = 0
        
        // the rectangle width.
        let rectWidth = pollResult * screenDivisions
        
        // the rectangle height.
        let rectHeight = 10
        
        // Create a CGRect object which is used to render a rectangle.
        let rectFrame: CGRect = CGRect(x:CGFloat(xPos), y:CGFloat(yPos), width:CGFloat(rectWidth), height:CGFloat(rectHeight))
        
        // Create a UIView object which use above CGRect object.
        let greenView = UIView(frame: rectFrame)
        
        // Set UIView background color.
        greenView.backgroundColor = UIColor.green
        
        //increment y position
        yPos = yPos + 25
        
        return greenView
        
    }

Solution

  • Cells of collection are dequeued dequeueReusableCell , you need to override prepareForReuse

    Or set a tag

    greenView.tag = 333
    

    And inside cellForItemAt do this

    cellB.resultsView.subviews.forEach {  
       if $0.tag == 333 {
          $0.removeFromSuperview()
        }
    }
    if receivedMessages[indexPath.row].pollResults != [] {
        for i in 0...receivedMessages[indexPath.row].pollResults.count - 1 {
            cellB.resultsView.addSubview(sq(pollSum: receivedMessages[indexPath.row].pollTotal!, pollResult: receivedMessages[indexPath.row].pollResults[i]))
        }
    }