Search code examples
swiftuicollectionviewuicollectionviewflowlayout

UICollectionView cells lining vertically instead of grid


I am trying to create UICollectionView programatically, and my cells are getting stacked vertically instead of a grid form. enter image description here

My code is:

    let layout:UICollectionViewFlowLayout = UICollectionViewFlowLayout()
    let screenSize: CGRect = UIScreen.main.bounds
    let screenWidth = screenSize.width

    let width = (screenWidth - 4)/3
    layout.itemSize = CGSize(width: width, height: width+20)
    layout.sectionInset = UIEdgeInsets(top:0,left:0,bottom:0,right:0)
    collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
    collectionView?.dataSource = self
    collectionView?.delegate=self
    collectionView?.collectionViewLayout = layout
    collectionView?.register(NearbyCollectionViewCell.self, forCellWithReuseIdentifier: "cellId")

    self.view.addSubview(collectionView!)

Solution

  • You should always consider collectionView's frame for item size calculation.

    In your question you are using UIScreen's width which might get you to wrong calculations because of collectionView's inset properties.

    let screenSize: CGRect = UIScreen.main.bounds

    let screenWidth = screenSize.width

    For correct size calculation lets define the number of items in single row.

    let maximumItemInRow = 3 (You can play with this as per your requirement)

    Now implementing the UICollectionViewDelegateFlowLayout's sizeForItem method.

     func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    
        // Getting collectionView's size
        var width = collectionView.frame.width
        var height = collectionView.frame.height
        
        // Respecting collectionView's ContentInsets properties
        width -= (collectionView.contentInset.left + collectionView.contentInset.right)
        height -= (collectionView.contentInset.top + collectionView.contentInset.bottom)
        
        if let flowLayout = collectionViewLayout as? UICollectionViewFlowLayout {
            
            // Respecting flowLayout's sectionInset properties
            width -= (flowLayout.sectionInset.left + flowLayout.sectionInset.right)
            height -= (flowLayout.sectionInset.top + flowLayout.sectionInset.bottom)
            
            // In Vertically scrolling Flow layout
            width -= flowLayout.minimumInteritemSpacing
            height -= flowLayout.minimumLineSpacing
        }
        
        // After considering contentInset and sectionInsets 
        // we can calculate the width according to 
        // number of items in single row. 
        return CGSize(width: width / maximumItemInRow, height: height)
    }