68

I have a tableView and in every tableViewCell is a collectionView.

I am trying to change the collectionView size with this code:

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

    if collectionView.tag == 2{

        return CGSize(width: 100, height: 100)

    }else if collectionView.tag == 4 {


        return CGSize(width: 222, height: 200)

    }else{


        return CGSize(width: 10, height: 10)
    }

}

The problem is that there is no error but cells do not change sizes

If you need to know something more, just write a comment.

Thank you.

0ndre_
  • 3,577
  • 6
  • 26
  • 44

7 Answers7

294

First, don't forget extends from UICollectionViewDelegateFlowLayout delegate.

For single collectionview display logic :

 func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    let width = ((collectionView.frame.width - 15) / 2) // 15 because of paddings
    print("cell width : \(width)")
    return CGSize(width: width, height: 200)
}

And important point in storyboard don't forget Estimate Size : None

estimate_size_none

Burak Dizlek
  • 4,805
  • 2
  • 23
  • 19
  • 26
    Wow. You saved my day. After changing the Estimate Size from Automatic to None(+ Min Spacing For Cells from 10 to 0 and For Lines from 10 to 0), func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) worked! Before the edit I was experiencing unexpected cell width and min spacing for cells. – mazend Nov 08 '19 at 11:09
  • 1
    Yes @mazend and I faced same problem. After a long time, I discovered by chance. I'm glad I could help you. – Burak Dizlek Nov 12 '19 at 06:42
  • 4
    I am using XCode 11.2.1 and this version has "Automatic" value as default for Estimate Size. So change it to None worked for me. Thanks man! – Rameez Dec 27 '19 at 12:57
  • Weird XCode additions... right answer for XCode 11.2.1, thanks :) – Onur Şahindur Mar 20 '20 at 15:11
  • 1
    Thanks for the estimated size point... wasted literally half a day on it debugging my size for item – Happiehappie May 08 '20 at 11:08
  • This is also needed if you use `xib`'s as well for your `collectionView` – Robert J. Clegg May 21 '20 at 15:45
  • UICollectionViewDelegateFlowLayout is the tricky part for me. – Thush-Fdo Oct 27 '20 at 15:23
  • Yes, it's working. After changing the Estimate Size from Automatic to None. – vivek May 05 '21 at 15:27
63

The signature for this method has changed in Swift 3 to:

func collectionView(_ collectionView: UICollectionView,
                    layout collectionViewLayout: UICollectionViewLayout,
                    sizeForItemAt indexPath: IndexPath) -> CGSize {
    // your code here
}

Pay attention to the subtle difference: (_ collectionView: ... instead of (collectionView: ....

This is because in Swift 3, you have to explicitly specify the label of the first parameter. You can override this default behaviour by adding the underscore character _.

Also, make sure that your class adopts both UICollectionViewDelegate and UICollectionViewDelegateFlowLayout protocols

class MyViewController: UICollectionViewDelegateFlowLayout, UICollectionViewDelegate {

    // your code here

    func collectionView(_ collectionView: UICollectionView,
                layout collectionViewLayout: UICollectionViewLayout,
                sizeForItemAt indexPath: IndexPath) -> CGSize {
        // your code here
    }
}

Refer to this link to learn more about changes in Swift 3.

mfaani
  • 33,269
  • 19
  • 164
  • 293
Pedro Mancheno
  • 5,237
  • 4
  • 24
  • 31
  • I have updated my code but it does not change the cell size :/ – 0ndre_ Oct 13 '16 at 16:08
  • 23
    add "UICollectionViewDelegateFlowLayout" in delgate call – Baljeet Singh Nov 02 '16 at 07:21
  • 4
    This is the right answer. Thank you so much for this! UICollectionViewDelegateFlowLayout is key – RanLearns Dec 16 '16 at 07:34
  • @BaljeetSingh what do you mean by "add "UICollectionViewDelegateFlowLayout" in delgate call"? – nambatee Dec 19 '17 at 20:18
  • 1
    @nambatee let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout() layout.sectionInset = UIEdgeInsets(top: -1, left: -1, bottom: -1, right: -1) let value:CGFloat = (UIScreen.main.bounds.width)/2; layout.itemSize = CGSize(width: value, height: value) layout.minimumInteritemSpacing = 0 layout.minimumLineSpacing = 0 GridView!.collectionViewLayout = layout – Baljeet Singh Dec 21 '17 at 10:26
  • for me it was UICollectionViewDelegateFlowLayout, previous developer didn't add that. – Ramesh Sanghar Sep 29 '22 at 07:12
23

You need to specify that you implement the protocol UICollectionViewDelegateFlowLayout in your class declaration.

class PhrasesCompactCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout
help-info.de
  • 6,695
  • 16
  • 39
  • 41
Vikas Krishnan
  • 241
  • 2
  • 7
5

So This is my code right now and it works:

        collectionView.delegate = dataSourceDelegate
        collectionView.dataSource = dataSourceDelegate
        collectionView.tag = row
        collectionView.setContentOffset(collectionView.contentOffset, animated:false)
        collectionView.reloadData()
        collectionView.register(UINib(nibName: "eventsCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "eventsCollectionViewCell")


        if row == 2{


            let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
            layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
            layout.itemSize = CGSize(width: 120, height: 120)
            layout.scrollDirection = .horizontal

            collectionView.collectionViewLayout = layout

        }else if row == 4 {


            let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
            layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
            layout.itemSize = CGSize(width: 222, height: 200)
            layout.scrollDirection = .horizontal

            collectionView.collectionViewLayout = layout

        }else{

            print("else")
        }
0ndre_
  • 3,577
  • 6
  • 26
  • 44
3

Short Version:

Try adding

collectionView.delegate = dataSource

Longer version:

For Me this was a small mistake -

collectionView.dataSource = self

This would call these methods

func numberOfSections(in collectionView: UICollectionView) -> Int
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell

However it would NOT call

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

Because this is not part of UICollectionView 's dataSource. It's part of UICollectionView's delegate.

So adding the following solved my issue.

collectionView.delegate = dataSource
BLC
  • 2,240
  • 25
  • 27
0

I've had the same problem! If you make the size half the width (width/2), then it will still appear like the entire width because the padding is being added to the width/2.

Fix: Make sure to set the section insets in Storyboard to 0. Alternatively, adjust the width/2 to a size that INCLUDES the section insets.

It took me a while to fix that one ;-)

t.berlin
  • 1
  • 1
-1

Don't forget to assign UICollectionViewFlowLayout object to your collectionViewLayout since UICollectionView uses UICollectionViewLayout (not UICollectionViewFlowLayout) by default.

let flowLayout = UICollectionViewFlowLayout()

collectionView.collectionViewLayout = flowLayout

Community
  • 1
  • 1
Valeria
  • 696
  • 6
  • 12