By Marko


2015-02-04 15:35:58 8 Comments

I'm trying to add UICollectionView to ViewController, and I need to have 3 cells 'per row' without blank space between cells (it should look like a grid). Cell width should be one third of screen size, so I thought that the layout.item width should be the same. But then I get this:

layout.itemSize width = screenSize.width/3

If I reduce that size (by 7 or 8 pixels e.g.), it's better, but the third cell in row is not completely visible, and I still have that blank space (top & bottom, and left & right) .

enter image description here

class ViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
    var collectionView: UICollectionView?
    var screenSize: CGRect!
    var screenWidth: CGFloat!
    var screenHeight: CGFloat!

    override func viewDidLoad() {
        super.viewDidLoad()

        screenSize = UIScreen.mainScreen().bounds
        screenWidth = screenSize.width
        screenHeight = screenSize.height

        // Do any additional setup after loading the view, typically from a nib
        let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
        layout.sectionInset = UIEdgeInsets(top: 20, left: 0, bottom: 10, right: 0)
        layout.itemSize = CGSize(width: screenWidth / 3, height: screenWidth / 3)
        collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
        collectionView!.dataSource = self
        collectionView!.delegate = self
        collectionView!.registerClass(CollectionViewCell.self, forCellWithReuseIdentifier: "CollectionViewCell")
        collectionView!.backgroundColor = UIColor.greenColor()
        self.view.addSubview(collectionView!)
    }

    func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
        return 1
    }

    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 20
    }

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier("CollectionViewCell", forIndexPath: indexPath) as CollectionViewCell
        cell.backgroundColor = UIColor.whiteColor()
        cell.layer.borderColor = UIColor.blackColor().CGColor
        cell.layer.borderWidth = 0.5
        cell.frame.size.width = screenWidth / 3
        cell.frame.size.height = screenWidth / 3

        cell.textLabel?.text = "\(indexPath.section):\(indexPath.row)"
        return cell
    }
}

8 comments

@A H M 2019-01-20 18:07:09

For Swift 3+ and Xcode 9+ Try using this

extension ViewController: UICollectionViewDelegateFlowLayout {

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

    let collectionWidth = collectionView.bounds.width
    return CGSize(width: collectionWidth/3, height: collectionWidth/3)

}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
    return 0
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
    return 0

}

@Alfi 2017-12-27 12:19:17

Swift 4

let collectionViewLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout
collectionViewLayout?.sectionInset = UIEdgeInsetsMake(0, 20, 0, 40) 
collectionViewLayout?.invalidateLayout()

@jamal zare 2017-10-08 10:19:59

let layout = myCollectionView.collectionViewLayout as? UICollectionViewFlowLayout
layout?.minimumLineSpacing = 8

@Dima Kozhevin 2017-10-08 10:34:43

Could you format your answer?

@Maor 2017-09-01 07:17:56

In Certain situations, Setting the UICollectionViewFlowLayout in viewDidLoador ViewWillAppear may not effect on the collectionView.

Setting the UICollectionViewFlowLayout in viewDidAppear may cause see the changes of the cells sizes in runtime.

Another Solution, in Swift 3 :

extension YourViewController : UICollectionViewDelegateFlowLayout{

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        return UIEdgeInsets(top: 20, left: 0, bottom: 10, right: 0)
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let collectionViewWidth = collectionView.bounds.width
        return CGSize(width: collectionViewWidth/3, height: collectionViewWidth/3)
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return 0
    }
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 20
    }
}

@jlstr 2017-10-12 22:20:58

Great Answer! This definitely is the Apple way to do it. Now, you don't happen to know how to refresh when device changes orientation, do you?

@Dharmendra Kachhadiya 2017-03-07 05:16:49

If you are looking for Swift 3, Follow the steps to achieve this:

func viewDidLoad() {

    //Define Layout here
    let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()

    //Get device width
    let width = UIScreen.main.bounds.width

    //set section inset as per your requirement.
    layout.sectionInset = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)

    //set cell item size here 
    layout.itemSize = CGSize(width: width / 2, height: width / 2)

    //set Minimum spacing between 2 items
    layout.minimumInteritemSpacing = 0

    //set minimum vertical line spacing here between two lines in collectionview
    layout.minimumLineSpacing = 0

    //apply defined layout to collectionview
    collectionView!.collectionViewLayout = layout

}

This is verified on Xcode 8.0 with Swift 3.

@Moin Shirazi 2017-02-06 12:01:09

For Swift 3 and XCode 8, this worked. Follow below steps to achieve this:-

viewDidLoad()
    {
        let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
        var width = UIScreen.main.bounds.width
        layout.sectionInset = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)
    width = width - 10
    layout.itemSize = CGSize(width: width / 2, height: width / 2)
        layout.minimumInteritemSpacing = 0
        layout.minimumLineSpacing = 0
        collectionView!.collectionViewLayout = layout
    }

@Nikhil Pandey 2017-04-04 06:08:04

How to take into account the fact if you have multiple sections

@user924 2019-04-12 21:10:35

it's only for 1 column (section)

@Nirmit Dagly 2016-10-26 14:56:18

For Swift 3 and XCode 8, this worked. Follow below steps to achieve this:-

{
    let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
    let width = UIScreen.main.bounds.width
    layout.sectionInset = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)
    layout.itemSize = CGSize(width: width / 2, height: width / 2)
    layout.minimumInteritemSpacing = 0
    layout.minimumLineSpacing = 0
    collectionView!.collectionViewLayout = layout
}

Place this code into viewDidLoad() function.

@MBH 2017-03-28 13:36:47

saved me couple of days to find this by myself. Thank you :)

@ssowri1 2017-07-31 16:56:07

Thank You! It's working awesome.

@Tushar Lathiya 2018-08-06 12:23:17

Working like charm..! Thanks

@user924 2019-04-12 21:13:00

it displays only one section in center, so useless!

@greentor 2015-02-04 17:02:52

Add these 2 lines

layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0

So you have:

   // Do any additional setup after loading the view, typically from a nib.
        let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
        layout.sectionInset = UIEdgeInsets(top: 20, left: 0, bottom: 10, right: 0)
        layout.itemSize = CGSize(width: screenWidth/3, height: screenWidth/3)
        layout.minimumInteritemSpacing = 0
        layout.minimumLineSpacing = 0
        collectionView!.collectionViewLayout = layout

That will remove all the spaces and give you a grid layout:

enter image description here

If you want the first column to have a width equal to the screen width then add the following function:

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
    if indexPath.row == 0
    {
        return CGSize(width: screenWidth, height: screenWidth/3)
    }
    return CGSize(width: screenWidth/3, height: screenWidth/3);

}

Grid layout will now look like (I've also added a blue background to first cell): enter image description here

@Marko 2015-02-05 07:36:34

Thank you so much, I was expecting something much more complicated, and I spent to much time on it. Thanks one more time.

@Marko 2015-02-05 08:15:54

And just one thing more, is there any possibility to change layout.itemSize for the first cell only? (I know that i need to change cell.frame.size when the indexPath.row is 0, but don't know how to change layout size only for one item) First element width should be equal screenWidth.

@greentor 2015-02-05 11:42:18

I've edited my answer to show how to change the cell width. Also, you don't need the size setting code in cellForItemAtIndexPath. You already set the size using layout.itemSize in viewDidLoad. The sizeForItemAtIndexPath function that I've added enables you to override the size. Hope that helps.

@Nada Gamal 2015-03-16 21:13:58

Hi, I have the same problem but i want to know the similar function title in Objective C .

@Nada Gamal 2015-03-16 21:22:59

Ok , It works fine now , Thanks a lot :) Objective C function : -(CGSize)collectionView:(UICollectionView )collectionView layout:(UICollectionViewLayout)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { return CGSizeMake(screenWidth/3, screenWidth/3); }

@Fattie 2016-06-29 21:23:13

thanks for the great answer @greentor. sent a bounty. Don't forget the collectionView!.collectionViewLayout = layout, readers

@iDeveloper 2016-11-05 06:44:02

Really helpful :)

@amjad 2016-12-05 17:25:52

I added my cell from storyboard not like this, how I can change the space?

@amjad 2016-12-05 17:26:41

@greentor Could you answer me please ?

@greentor 2016-12-05 18:23:02

@amjad hava a look at github.com/petetodd/BGSEmbeddedCVSwift for an example. In the storyboard size inspector you can change some of the collection view layout settings but you will probably need to do some calculations and set some layout values in the code.

@amjad 2016-12-05 18:40:48

@greentor thank you, but what if I want a little space between the columns "like 4 or 5" what I should change in the code ? because when I write layout.minimumInteritemSpacing = 4 doesn't work well

@greentor 2016-12-05 18:54:03

@amjad you will need to adjust the size of the collection view cell (the line return CGSize(width: screenWidth/3, height: screenWidth/3))

@amjad 2016-12-05 19:13:56

@greentor Thank you very much, that's work

Related Questions

Sponsored Content

4 Answered Questions

[SOLVED] Swift Error - Use of undeclared type 'cell' - Collection View

14 Answered Questions

3 Answered Questions

[SOLVED] Expand and Collapse tableview cells

9 Answered Questions

[SOLVED] How to detect tableView cell touched or clicked in swift

24 Answered Questions

[SOLVED] Cell spacing in UICollectionView

1 Answered Questions

[SOLVED] Swift vertical UICollectionView inside UITableView

2 Answered Questions

How to show images from API in CollectionView

2 Answered Questions

1 Answered Questions

[SOLVED] UICollectionView not displayed iOS8

4 Answered Questions

[SOLVED] Dynamic size UICollectionView cell

Sponsored Content