swiftuicollectionviewuicollectionviewcelluicollectionviewdelegateflowlayout

Scaling down the height of a UICollectionViewCell dynamically


I am using UICollectionViewDelegateFlowLayout to display cells of dynamic height in my Collection View. The size of the cells are set in sizeForItemAt.

Goal: Each Collection View cell has a toggle function that should change the dynamically-calculated height to 50%. This is where I am running into problems.

In sizeForItemAt I am getting the dynamic height.

var dynamicHeight = (header + content + footer)
return CGSize(width: self.view.frame.width, height: dynamicHeight)

I'd like to update sizeForItemAt to something like the following, when a button on the cell gets pressed:

return CGSize(width: self.view.frame.width, height: (dynamicHeight / 2))

How do I change the height of a Collection View Cell while updating sizeForItemAt?


Solution

  • In order to achieve what you want you need to:

    You can see an example in the following code:

    class TestCollectionViewCell: UICollectionViewCell {
        @IBOutlet weak var `switch`: UISwitch!
        var action: ((Bool) -> Void)?
        
        @IBAction func switchValueChanged(_ sender: UISwitch) {
            action?(sender.isOn)
        }
    }
    

    private let reuseIdentifier = "Cell"
    
    class TestCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
        struct Item {
            let color: UIColor
            var scaledDown: Bool
        }
    
        var items: [Item] = [
            .init(color: .red, scaledDown: false),
            .init(color: .green, scaledDown: false),
            .init(color: .black, scaledDown: false),
            .init(color: .orange, scaledDown: false),
            .init(color: .yellow, scaledDown: false),
            .init(color: .gray, scaledDown: false),
            .init(color: .darkGray, scaledDown: false),
            .init(color: .lightGray, scaledDown: false),
        ]
    
        // MARK: UICollectionViewDataSource
    
        override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
            return items.count
        }
    
        override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! TestCollectionViewCell
            let item = items[indexPath.item]
            
            cell.switch.isOn = item.scaledDown
            cell.backgroundColor = item.color
            cell.action = { [weak self] (isOn: Bool) in
                guard let self = self else { return }
                self.items[indexPath.item].scaledDown = isOn
                collectionView.reloadItems(at: [indexPath])
            }
        
            return cell
        }
        
        // MARK: - UICollectionViewDelegateFlowLayout
        
        func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
            let dynamicHeight: CGFloat = 200
            if items[indexPath.item].scaledDown {
                return CGSize(width: view.frame.width, height: (dynamicHeight / 2))
            }
            return CGSize(width: view.frame.width, height: dynamicHeight)
        }
    }
    

    enter image description here