1

Hi I am creating an app which requires a grid of images. As an example I am using a 2x2 grid of images in cells of a UICollectionView. I would like to know how I could decrease the annoying space in the middle and also make them have equal widths and heights to fit the whole screen. I know that I can do this with Interface builder. However, I want to do this programmatically because as the app progresses, there will be different levels and different number of squares - possibly a 10x10 also. I am new to UICollectionViews. I have referenced to many other questions, however most are in Objective C and there few that are in Swift don't seem to work with Swift 3.

Here is my full code:

import UIKit

class GameViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout{

@IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.
    collectionView.delegate = self
    collectionView.dataSource = self
let collectionViewLayout = self.collectionView.collectionViewLayout as! UICollectionViewFlowLayout
    collectionViewLayout.minimumLineSpacing = 0
    collectionViewLayout.minimumInteritemSpacing = 0

}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}


func numberOfSections(in collectionView: UICollectionView) -> Int {
    return 2;
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return 2
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)


    let image = cell.viewWithTag(1) as! UIImageView
    image.image = #imageLiteral(resourceName: "coffee")

    return cell;
}


func collectionView(_collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {

    return CGSize(width: self.collectionView.frame.size.width/2, height: self.collectionView.frame.size.height/2)
    //this method is not getting called 

}




}

I am also uploading an image of how it currently is and how I want it to be-

enter image description here

enter image description here

I hope you guys will help me- it will be very useful... Thanks!

I conformed to UICollectionViewDelegateFlowLayout and called sizeforitematindexpath but it did not work. On adding a breakpoint I realized that the method was not getting called. So is there anything wrong I'm doing here. Also Xcode gives me this warning - enter image description here

Aryan C
  • 407
  • 1
  • 3
  • 12

4 Answers4

4

Make sure that:

  • Confirming to UICollectionViewDelegateFlowLayout.
  • collectionView's width = screen's width.
  • Min Spacing for cells is zero. You can change it from the Interface Builder (Select the collectionView -> show size inspector -> set min spacing to 0), or by implementing minimumInteritemSpacingForSectionAt returning zero.
  • If you want to fill the whole Screen height (I am asking because this is not what provided in your screenshot), collectionView's height = screen's height.

Finally, implement sizeForItemAtIndexPath method:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {        
    return CGSize(width: collectionView.frame.width / 2, height: 100)
}
Ahmad F
  • 30,560
  • 17
  • 97
  • 143
  • Thanks for the reply but it doesn't seem to work.. I noticed that if I change the size of cells from interface builder, the cell size changes on running the app as well but when I try to edit it in code by conforming to UICollectionViewDelegateFlowLayout, it seems to remain unchanged. – Aryan C Oct 10 '16 at 12:34
  • add a breakpoint to the method on the return line, does it reached? – Ahmad F Oct 10 '16 at 12:38
  • I think that I got your point :) your are using Swift 3, I edited the code snippet. – Ahmad F Oct 10 '16 at 12:49
  • Thanks that worked... nut now the question is how I can change the size of the image in the cell – Aryan C Oct 10 '16 at 13:00
  • by adding constraints to the UIIMageView in the interface builder. Make sure it has the same cell size and add 4 constraints: leading, trailing, top and bottom and set the constant for all of them to zero, this will automatically let image size to expand. Don't forget to change the content mode as desired. I think that's all :) – Ahmad F Oct 10 '16 at 13:11
  • Great! Thanks you guys have helped me a lot! – Aryan C Oct 10 '16 at 13:18
3

Use following code in viewDidLoad

let collectionViewLayout = self.collectionView.collectionViewLayout as! UICollectionViewFlowLayout
        collectionViewLayout.minimumLineSpacing = 0
        collectionViewLayout.minimumInteritemSpacing = 0
        collectionViewLayout.itemSize = CGSize(width: UIScreen.main.bounds.width/2, height: UIScreen.main.bounds.width/2)
Sandeep Kumar
  • 328
  • 1
  • 8
2

Use "UICollectionViewDelegateFlowLayout" Delegate for set size for CollectionView cell size

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: UIScreen.main.bounds.width/2, height: UIScreen.main.bounds.width/2)
    }

I hope this will helpfull for you.

Sandeep Kumar
  • 328
  • 1
  • 8
  • return CGSize(width: UIScreen.main.bounds.width/2, height: UIScreen.main.bounds.width/2) will make it square based on the width of UIScreen.main.bounds. – Ahmad F Oct 10 '16 at 12:21
  • 1
    Yes, This will make square. We can change size as per requirement. – Sandeep Kumar Oct 10 '16 at 12:25
  • Thanks guys for your quick replies, I really do appreciate it. However conforming to UICollectionViewDelegateFlowLayout does not seem to do any good... I implemented sizeForItemAtIndexPath but on adding a breakpoint it seems like the method is not being called... – Aryan C Oct 10 '16 at 12:39
  • let collectionViewLayout = self.collectionView.collectionViewLayout as! UICollectionViewFlowLayout collectionViewLayout.minimumLineSpacing = 0 collectionViewLayout.minimumInteritemSpacing = 0 collectionViewLayout.itemSize = CGSize(width: UIScreen.main.bounds.width/2, height: UIScreen.main.bounds.width/2) – Sandeep Kumar Oct 10 '16 at 12:44
1

You can use the following to size the cells:

extension GameViewController: UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let cellWidth = self.collectionView.bounds.width / 2
        return CGSize(width: cellWidth, height: cellWidth)
    }
}

Also, add the following lines at the end of viewDidLoad() to get rid of the unwanted white space:

let collectionViewLayout = self.collectionView.collectionViewLayout as! UICollectionViewFlowLayout
collectionViewLayout.minimumLineSpacing = 0
collectionViewLayout.minimumInteritemSpacing = 0
Sebastian
  • 526
  • 2
  • 15
  • Thanks for the reply but it doesn't seem like conforming to UICollectionViewDelegateFlowLayout is doing any good... – Aryan C Oct 10 '16 at 12:36
  • Oh I just put a breakpoint in sizeForItemAt indexPath and realized that the method is not getting called! I have conformed to UICollectionViewDelegateFlowLayout though... – Aryan C Oct 10 '16 at 12:40
  • Just for the sake of testing, try removing "weak" from the collectionView IBOutlet. – Sebastian Oct 10 '16 at 12:42
  • Did it.. no difference – Aryan C Oct 10 '16 at 12:53
  • Just saw your edit. You're using swift 2 syntax. Try copying my answer :). – Sebastian Oct 10 '16 at 12:56
  • Thanks!! works but what is the point of Apple of making minor changes in the syntax every year with every new release of Swift. it makes it hard for us developers...I spent a lot of time on this... – Aryan C Oct 10 '16 at 13:04
  • I know, we're all in the same boat :( – Sebastian Oct 10 '16 at 13:04