SimpuMind
SimpuMind

Reputation: 469

Swift: Different number of cells in a row of a UICollectionView iOS

I want to mix the layout flow of a UICollectionView to both vertical and horizontal, i want to have every row divisible by 2 to have a single item, else it should have a two column grid, i have exhausted every approach i can think of, i end of getting one item per row.

The image below is exactly what i want to achieve.

enter image description here

This is what i tried

    class TrendVC: UIViewController {

    fileprivate let itemsPerRow: CGFloat = 2

    fileprivate let sectionInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)

    @IBOutlet weak var collectionView: UICollectionView!

    var data = [ "others", "sports", "kitchen", "phones", "entertainment", "electronics", "women"]
    var dataNames = ["Bags", "Sports & Outdoor", "Kitchen Essentials", "Mobile Phones & Tablets", "Entertainment", "Audio and Video", "Women's Clothings"]

    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = .white

                navigationController?.navigationBar.isTranslucent = true
                navigationController?.navigationBar.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
                navigationController?.navigationBar.shadowImage = UIImage()

        collectionView.dataSource = self
        collectionView.delegate = self

        collectionView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)

    }


}

extension TrendVC: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout{

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

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

        if indexPath.item % 3 == 0{

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

            let datum = data[indexPath.item]

            let dat = dataNames[indexPath.item]

            cell.trendNameLabel.text = dat

            cell.trendImageView.image = UIImage(named: datum)

            return cell
        }else{
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TrendCell", for: indexPath) as! SingleTrendCell

            let datum = data[indexPath.item]

            let dat = dataNames[indexPath.item]

            cell.trendNameLabel.text = dat

            cell.trendImageView.image = UIImage(named: datum)

            return cell
        }
    }


    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

        if indexPath.item % 3 == 0{
            let paddingSpace = sectionInsets.left * (2 + 1)
            let availableWidth = view.frame.width - paddingSpace
            let widthPerItem = availableWidth / itemsPerRow

            return CGSize(width: widthPerItem, height: widthPerItem)
        }
        let paddingSpace = sectionInsets.left * (2 + 1)
        let availableWidth = view.frame.width - paddingSpace
        let widthPerItem = availableWidth / itemsPerRow
        return CGSize(width: view.frame.width, height: widthPerItem)

    }

    //3
    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        insetForSectionAt section: Int) -> UIEdgeInsets {
        return sectionInsets
    }

    // 4
    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return sectionInsets.left
    }
}

This is what i am getting

enter image description here

Upvotes: 3

Views: 3662

Answers (2)

Rikh
Rikh

Reputation: 4222

Since both your cells have the same structure, there is not point in creating two different kinds of cells. All you have to do is use the sizeForItemAtIndexPath method and return appropriate sizes, autoLayout will take care of the content inside. Something like:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

    if indexPath.item % 3 == 0{

        return CGSize(width: collectionView.bounds.size.width/2.0, height: collectionView.bounds.size.height/3.0)

    }else{

        return CGSize(width: collectionView.bounds.size.width, height: collectionView.bounds.size.height/3.0)
    }
}

Note: Ensure all your insets and inter item spacings are 0.

Upvotes: 2

Nirav D
Nirav D

Reputation: 72410

You need to calculate modulo with 3 instead of 2 to get the desired output.

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    if indexPath.item % 3 == 0{
        //return SingleTrendCell
    }else{
        //return DoubleTrendCellCell
    }
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

    if indexPath.item % 3 == 0{
        //return SingleTrendCell Size
    }
    //return DoubleTrendCellCell Size

}

Upvotes: 1

Related Questions