3

I have collectionView with constraint to superview. I want to get this result for iPhone X:

enter image description here

But I get this:

enter image description here

How to fix it?

code:

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

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

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


        cellOffset = 10

        cellWidth = (667 / 3)  - (cellOffset * 4)
        cellHeight =  (cellWidth / 2 * 3) + (cellWidth / 2 * 0.65)

        return CGSize(width: cellWidth, height: cellHeight)
    }

Update

enter image description here

Update

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

        let sectionInset = collectionView.frame.width / 3.0
        let margins = CGFloat(10.0 * 2.0)
        let width = (collectionView.frame.width - sectionInset - margins) / 3.0
        let height = collectionView.frame.height - 40.0

        let collectionViewLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout
        collectionViewLayout?.sectionInset = UIEdgeInsets(top: 0, left: 6.0, bottom: 0, right: 6.0)
        collectionViewLayout?.minimumInteritemSpacing = 10
        collectionViewLayout?.invalidateLayout()

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

result:

enter image description here

user291334
  • 77
  • 1
  • 10

5 Answers5

1

If you want 3 cells in landscape

let cellWidth = ( self.collectionView.frame.width - 2 * cellOffset ) / 3
Shehata Gamal
  • 98,760
  • 8
  • 65
  • 87
0
 func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {



    return CGSize(width: collectionView.frame.size.width/4 - 1, height: collectionView.frame.size.width/4 - 1)
}
  • For all devices everything works fine. When I launch my app on my iPhone X cells are in the middle and have same distance between 1 cell and left screen edge and between 3 cell and right screen edge. But when I tap on collectionView or start scroll my cells shift to left screen edge and if I continue scroll my other sections in `numberOfSections(in collectionView: UICollectionView)` will be not are in the middle. – user291334 Jul 14 '18 at 07:03
  • When app start my collectionView appears not in the center - https://streamable.com/c4kpx – user291334 Jul 16 '18 at 07:27
0

My suggestion would be to consider refactoring your layout a tad such that each section is inset on the left and right by the margin you're looking for. You could then describe your cell size in the following manner:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    let sectionInset = collectionView.frame.width / 3.0
    let margins = CGFloat(10.0 * 2.0)
    let width = (collectionView.frame.width - sectionInset - margins) / 3.0
    let height = collectionView.frame.height - 40.0

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

Next you'd want to return this section inset value in the appropriate delegate method. Let's assume you want to reserve the first and last sixth of the collection view for this margin, which is roughly what your image shows.

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    return UIEdgeInsets(top: 0,
                        left: collectionView.frame.width / 6.0,
                        bottom: 0,
                        right: collectionView.frame.width / 6.0)
}

Putting it all together, we end up with this revision:

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

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

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    let sectionInset = collectionView.frame.width / 3.0
    let margins = CGFloat(10.0 * 2.0)
    let width = (collectionView.frame.width - sectionInset - margins) / 3.0
    let height = collectionView.frame.height - 40.0

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

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

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    return UIEdgeInsets(top: 0,
                        left: collectionView.frame.width / 6.0,
                        bottom: 0,
                        right: collectionView.frame.width / 6.0)
}
woodcutting
  • 271
  • 1
  • 9
  • I do not quite understand your code. What values I should paste in `section inset`, `cell margins ` `ratio `? . And how to use 2 part of your code - `(UIEdgeInsets)`? – user291334 Jul 14 '18 at 06:46
  • I edited my answer to provide more detail, and tested the result. If you want to see more snappy paging behavior, you should try `collectionView.isPagingEnabled = true`. – woodcutting Jul 14 '18 at 13:35
  • This is work. But this is a good solution for the iPhone X. For other devices, I want to save the code in my question (with changes 667 to view.frame.width). Because in my code I have a special aspect of the cell. And in your code my aspects for other devices breaks. How to implement your code only for iPhone X? – user291334 Jul 14 '18 at 16:38
  • Is the aspect ratio you want to use consistent across different devices? If so, you could change the line where height is determined to just use your aspect ratio. – woodcutting Jul 14 '18 at 18:41
  • [Here](https://stackoverflow.com/questions/46192280/detect-if-the-device-is-iphone-x) is some advice on checking device type if its necessary to do so. – woodcutting Jul 14 '18 at 21:31
  • I want to use your code inside one function. I add code example in question and screen. On my screen I haven't space between my sections consisting of 3 cells. – user291334 Jul 15 '18 at 05:57
  • It is works but I have some problems with collectionView. When app start my collectionView appears not in the center - https://streamable.com/c4kpx – user291334 Jul 16 '18 at 07:26
0

You need to set layout of collection view by this one.

// setup collection view
let numberItemPerRow = 4
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 1, left: 0, bottom: 1, right: 0)
layout.itemSize = CGSize(width: ScreenSize.width/numberItemPerRow-1, 
                         height: ScreenSize.width/numberItemPerRow)
layout.minimumInteritemSpacing = 1
layout.minimumLineSpacing = 1
your_collection.collectionViewLayout = layout

I guarantee that this code will be solved. !!

0

You are making it a bit too complicated. It's just about playing a bit with the insets and the size. Here is the example code:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    return UIEdgeInsetsMake(0, 145, 0, 145)
}

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

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

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

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    return CGSize(width: self.view.frame.width / 3 - 100 , height: collectionView.frame.size.height - 100)
}

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

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

Here is the image of what it gives:

enter image description here

Update

import UIKit

class ViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource, UICollectionViewDelegate {

    lazy var collectionView : UICollectionView = {
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .horizontal
        let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
        cv.backgroundColor = .green
        cv.isPagingEnabled = true
        cv.delegate = self
        cv.dataSource = self
        return cv
    }()


    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.addSubview(collectionView)
        collectionView.register(Cell.self, forCellWithReuseIdentifier: "cell")
        collectionView.frame = self.view.frame
        collectionView.contentInset = UIEdgeInsetsMake(0, -45, 0, -45)
    }


    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        return UIEdgeInsetsMake(0, 145, 0, 145)
    }

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

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

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

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: self.view.frame.width / 3 - 100 , height: collectionView.frame.size.height - 100)
    }

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

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

}

class Cell : UICollectionViewCell {


    override init(frame: CGRect) {
        super.init(frame: frame)
        setupViews()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func setupViews() {
        self.backgroundColor = .red
    }

}
Galo Torres Sevilla
  • 1,540
  • 2
  • 8
  • 15
  • It is works but I have some problems with collectionView. When app start my collectionView appears not in the center - https://streamable.com/c4kpx – user291334 Jul 16 '18 at 07:26
  • Just set the collectionView.contentInset. In the example that I gave you these are the values collectionView.contentInset = UIEdgeInsetsMake(0, -45, 0, -45) – Galo Torres Sevilla Jul 16 '18 at 10:15
  • But in this case cells have different size. – user291334 Jul 16 '18 at 10:26
  • Yes, but I'm giving you the function that you need to make it work. Finding the values is just doing some quick math. – Galo Torres Sevilla Jul 16 '18 at 10:29
  • It is not help. Look at scroll indicator. The problem remains https://streamable.com/eh77l – user291334 Jul 16 '18 at 10:40
  • What exactly are you doing? of course that will happen if you have cells expanding from edge to edge of the collection view and you set a negative content inset. The negative values are for what you first described in your question. Here is the example working: https://streamable.com/3h6n3 – Galo Torres Sevilla Jul 16 '18 at 10:56
  • I create new project and add collectionView I have same issue. Could you give me your project, please. If this is not difficult for you to do? So that I could compare my collectionView and yours. I can't find issue. – user291334 Jul 16 '18 at 13:16
  • Where the 100 in item width came from? – rami Oct 11 '22 at 12:53