0

So basically I have a collection view layout that looks like this:

enter image description here

which is a 3 per row image that is super close to each other like instagram. The problem here is that when I go to an ipad or a smaller phone like iphone se the layout gets distorted. This is what it looks like on an ipad

enter image description here

The collection view layout code is this:

    func callCustomFlowLayout(collectionView: UICollectionView) {
    let flow = collectionView.collectionViewLayout as! UICollectionViewFlowLayout

    let itemSpacing: CGFloat = 1
    let itemsInOneLine: CGFloat = 3
    flow.sectionInset = UIEdgeInsetsMake(0, 0, 0, 0)
    let width = UIScreen.main.bounds.size.width - itemSpacing * CGFloat(itemsInOneLine - 1) //collectionView.frame.width is the same as  UIScreen.main.bounds.size.width here.
    flow.itemSize = CGSize(width: floor(width/itemsInOneLine), height: width/itemsInOneLine)
    flow.minimumInteritemSpacing = 1
    flow.minimumLineSpacing = 1
}

Thanks for any future help. I just want it to be 3 images per rows and adjusting the image size based on the size of the device.

Here is my layout code

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

    let cellsAcross: CGFloat = 3
    let spaceBetweenCells: CGFloat = 1
    let dim = (collectionView.bounds.width - (cellsAcross - 1) * spaceBetweenCells) / cellsAcross

    return CGSize(width: dim, height: dim)
}
rmaddy
  • 314,917
  • 42
  • 532
  • 579
Jov
  • 31
  • 1
  • 9
  • https://stackoverflow.com/a/38028456/1630618 – vacawama Jul 01 '18 at 11:50
  • I tried the answer there and it didn't work.. @vacawama – Jov Jul 01 '18 at 12:17
  • You probably have to adopt `UICollectionViewDelegateFlowLayout` for your class. – vacawama Jul 01 '18 at 12:20
  • you mean set the delegate for that? – Jov Jul 01 '18 at 12:23
  • Add `UICollectionViewDelegateFlowLayout` to your `class` definition line. – vacawama Jul 01 '18 at 12:29
  • ah yes I already extended it and it gets called too as I just debugged it but it still doesn't give 3 images per rows and even on the iphones. – Jov Jul 01 '18 at 12:31
  • Try implementing the FlowLayout method for interim spacing and return the `spaceBetwenCells` value. `func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { return spaceBetweenCells }` – vacawama Jul 01 '18 at 12:41
  • I tried it and it still didn't work. Can you perhaps make like a sample git project with this even if just for this one feature. – Jov Jul 01 '18 at 12:54

2 Answers2

0

Override UICollectionView like this:

class UICollectionViewCustom: UICollectionView {

    public override var bounds: CGRect {
        didSet {
            collectionViewLayout.invalidateLayout()
        }
    }
}

This updates collectionView layout whenever collectionView resized.

Adem Özgür
  • 200
  • 1
  • 10
  • Have you pinned the collection view to parent view to resize with screen width? – Adem Özgür Jul 01 '18 at 12:20
  • Yes it's leading trailing and bottom is attached to the superview – Jov Jul 01 '18 at 12:22
  • can you share your func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize implementation also? – Adem Özgür Jul 01 '18 at 12:32
  • Hi Adem thanks for your help.. I edited my post to add the sizeforitem at implementation – Jov Jul 01 '18 at 12:36
  • That calculation uses collectionview's initial width, before layout pass. You need to update layout when collectionview size changes with invalidateLayout(). I had the same problem a few days ago. The above solution should resolve. BTW did you update the collectionView class in your nib/ storyboard file? – Adem Özgür Jul 01 '18 at 13:01
0
class CollectionView: UICollectionView {

    private let numberOfCellsPerRow = 3
    private let spacing: CGFloat = 1

    private var flowLayout: UICollectionViewFlowLayout? {
        return collectionViewLayout as? UICollectionViewFlowLayout
    }

    override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
        super.init(frame: frame, collectionViewLayout: layout)
        sharedInit()
        updateItemSize()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        sharedInit()
        updateItemSize()
    }

    private func sharedInit() {
        flowLayout?.minimumInteritemSpacing = spacing
        flowLayout?.minimumLineSpacing = spacing
    }


    private func updateItemSize() {
        let cellWidth = floor((bounds.width - (CGFloat(numberOfCellsPerRow) - 1) * spacing) / CGFloat(numberOfCellsPerRow))
        flowLayout?.itemSize = CGSize(width: cellWidth, height: cellWidth)
        flowLayout?.invalidateLayout()
    }

    override var bounds: CGRect {
        didSet {
            if bounds != oldValue {
                updateItemSize()
            }
        }
    }
}

Results in:

iphone ipad

André Slotta
  • 13,774
  • 2
  • 22
  • 34
  • Thank you! I figured it out because of all your answers. Apparently my collection view was trying to do this but the image view's constraint wasn't being used because I didn't put constraint to the image inside the cell. – Jov Jul 02 '18 at 03:47