Set collectionView size. (sizeForItemAtIndexPath function is not working) Swift 3
Asked Answered
C

7

69

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.

Constringe answered 13/10, 2016 at 11:35 Comment(2)
Your first statement says you have a tableView, but this looks like a collectionView. Do you have both, or just one?Waterlog
@Waterlog there is a collection view inside table view cellConstringe
C
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")
        }
Constringe answered 13/10, 2016 at 16:49 Comment(1)
What is row? How and where its declared and assigned?Duodenum
F
302

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

Ferryboat answered 7/11, 2019 at 15:7 Comment(8)
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.Varion
Yes @Varion and I faced same problem. After a long time, I discovered by chance. I'm glad I could help you.Ferryboat
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!Tui
Weird XCode additions... right answer for XCode 11.2.1, thanks :)Mitten
Thanks for the estimated size point... wasted literally half a day on it debugging my size for itemJerrelljerri
This is also needed if you use xib's as well for your collectionViewWandawander
UICollectionViewDelegateFlowLayout is the tricky part for me.Brenza
Yes, it's working. After changing the Estimate Size from Automatic to None.Sterigma
F
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.

Frizzy answered 13/10, 2016 at 11:48 Comment(6)
I have updated my code but it does not change the cell size :/Constringe
add "UICollectionViewDelegateFlowLayout" in delgate callWilen
This is the right answer. Thank you so much for this! UICollectionViewDelegateFlowLayout is keyHeddy
@BaljeetSingh what do you mean by "add "UICollectionViewDelegateFlowLayout" in delgate call"?Madelenemadelin
@Madelenemadelin 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 = layoutWilen
for me it was UICollectionViewDelegateFlowLayout, previous developer didn't add that.Dogface
S
23

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

class PhrasesCompactCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout
Schach answered 30/1, 2017 at 17:33 Comment(0)
C
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")
        }
Constringe answered 13/10, 2016 at 16:49 Comment(1)
What is row? How and where its declared and assigned?Duodenum
V
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
Vaseline answered 6/4, 2017 at 9:26 Comment(1)
Why are you setting collectionView.delegate = dataSource instead of collectionView.delegate = selfInstill
I
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 ;-)

Indecent answered 18/7, 2017 at 12:16 Comment(0)
K
-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

Knocker answered 16/12, 2019 at 15:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.