5

I am trying to create 2x2 grid layout using collection view.

I have used below code. It's kind of working fine for iPhone 5 but with tweaks. I am trying to write code that can be used on all screen sizes. This is not working on iPhone 6.

public func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 2
    }

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

    public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
        if let cell1 = cell as? CollectionViewCell {
            return cell1
        }
        return cell
    }

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

        let padding: CGFloat =  20
        let collectionViewSize = collectionView.frame.size.width - padding

        return CGSize(width: collectionViewSize/2, height: collectionViewSize/2+15)
    }

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

    public func collectionView(
        _ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

    }

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

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

I am trying to achieve following layout: Expected

In future this grid can be like 2 columns only and N rows. Each row will always have 2 items.

3
  • What is the issue on iPhone 6? Commented Sep 19, 2019 at 9:22
  • In iPhone 6, space between two rows increases. Even in iPhone 5, i am giving additional 15 to maintain space. I dont want to hard code. Commented Sep 19, 2019 at 9:23
  • github.com/cp-satish-v/MosaicLayoutDemo Commented Mar 31, 2021 at 9:32

3 Answers 3

3

First of all, get three variables together depending on your needs. Those are the minimum spacing (Both InteritemSpacing and Line spacing - Should be same UXwise but you can change that in delegate methods if you like. The interitem space however must always be equal to minimumSpacing), edgeInsetPadding and the number of items you want in a row.

private var numberOfItemsInRow = 2

private var minimumSpacing = 5

private var edgeInsetPadding = 10

In your code, you have already defined your Edge Insets as:

 UIEdgeInsets(
            top: 5, left: 5, bottom: 5, right: 5
        )

The left and right insets are important for correctly determining the size of the item. left+right gives us a grand sum of 10. This should be assigned to edgeInsetPadding like this:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        let inset = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)
        edgeInsetPadding = inset.left+inset.right
        return inset
    }

Now lets get to your UICollectionViewDelegateFlowLayout. Update the following methods.

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

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

Now lets get to the main part. Modify your sizeForItemAt in UICollectionViewDelegateFlowLayout as:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let width = (Int(UIScreen.main.bounds.size.width) - (numberOfItemsInRow - 1) * minimumSpacing - edgeInsetPadding) / numberOfItemsInRow
        return CGSize(width: width, height: width)
    }

And this is it. You now get two equal size tiles in 2x2 grid. If you want to change this in future, just change the numberOfItemsInRow variable to something else. Like 3 for 3x3.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you, for explaining it so clearly.Your solution worked for me. But only problem which I faced is there is empty space at bottom of screen. I changed cell height to resolve this. Also I changed edge insets to 5 to fit it into 2 columns. Checked on iPhone 5, 6 and 6 plus.
3

This will be done using the item size of the collectionViewCell

collectionView.delegate = self 
extension ViewController : UICollectionViewDelegateFlowLayout {

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let padding = 5
        let width = (collectionView.frame.size.width - CGFloat(padding) * 2) / CGFloat(2)
        let height = width / 200 * 110 // or what height you want to do
        return CGSize(width: width, height: height)
    }
}

Comments

0

Use:

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

        let padding: CGFloat =  20
        let size = self.view.frame.width - padding

        return CGSize(width: size/2, height: size/2+15)
    }

1 Comment

Cell will layout itself inside CollectionView so it's not a good idea to use collectionView's parent frame.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.