Ios – Swift 3: Resizing UICollectionViewCell programmatically causes cells to overlap

iosswiftswift3uicollectionviewuicollectionviewcell

I am trying to create a UICollectionView with 3 cells below each other.
This is working properly. When I touch one cell, this cell should expand, the others should collapse to a specific height. Also working just fine.

The problem which I cannot solve; when I tap a cell, and it expands like I wanted it to; it overlaps the one below this one. The one below does not move down to make room for this cells new height.

How can I fix this?

This is what I have so far related to the UICollectionView and UICollectionViewCell

/**
 * Tempory 3 items
 */
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return 3
}

/**
 * Defining the cells
 */
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! LicenseplateCollectionViewCell

    cell.backgroundColor = .white
    cell.layer.cornerRadius = 4

    if(indexPath.row > 0){
        cell.carStack.isHidden = true
    }

    return cell
}


/**
 * Initial size
 */
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    // The first cell always start expanded with an height of 300
    if(indexPath.row == 0){
        return CGSize(width: collectionView.bounds.size.width, height: 300)
    }else{
        // The others start with an height of 80
        return CGSize(width: collectionView.bounds.size.width, height: 80)
    }
}

/**
 * This functio shoud be handling everything like an accordeon system.
 * When I touch one cell, the others should collapse.
 */
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

    // Animate resize of cell after tapping
    UIView.animate(withDuration: 0.2, animations: {
        // For now I have 3 cells, which I will loop
        for i in 0...2{
            // If this is the active cell (I just tapped on) ...
            if(indexPath.row == i){
                let cell = collectionView.cellForItem(at: indexPath) as! LicenseplateCollectionViewCell
                // This cell is expanded already, collapse it
                if(cell.frame.size.height > 200){
                    cell.carStack.isHidden = true
                    cell.frame.size = CGSize(width: collectionView.bounds.size.width, height: 80)
                }else{
                    // Open up this cell
                    cell.carStack.isHidden = false
                    cell.frame.size = CGSize(width: collectionView.bounds.size.width, height: 300)
                }
            }else{
                // Other cells besides the one I just tapped, will be collapsed
                print(indexPath.row, indexPath.section)
                let customPath = IndexPath(row: i, section: 0)
                print(customPath.row, customPath.section)
                let cell = collectionView.cellForItem(at: customPath) as! LicenseplateCollectionViewCell
                cell.carStack.isHidden = true
                cell.frame.size = CGSize(width: collectionView.bounds.size.width, height: 80)
            }
        }
    })

}

Best Answer

I have solved this. The animation/resize should not happen in the didSelectItemAt override.

At first I have to define the array with cell configurations properly. Here I add a key 'active' with an boolean.

When I tap a cell, I switch the 'active' boolean to true within the objects array, and after that just call collectionView.reloadData(), this executes the sizeForItemAt override before the UICollectionView has been shown. This ensures the cell's are properly aligned and do exactly what they should do.

In the sizeForItemAt I return the proper height based on the 'active' boolean within the objects array.

Related Topic