0

I am working with a UICollectionView using UICollectionViewFlowLayout and have some difficulties to understand item sizing an spacing. I know that there several methods to adapt sizing and spacing (using the delegate methods, overriding FlowLayout, etc.). However without understanding the logic behind these values in the first place, it is quite hard to adapt them properly.

The following results have been created a default UICollectionViewController with a default UICollectionViewCell without any subclasses. Only the following settings haven been made:

  • Specified the cell size to be 200 x 200 in IB
  • Placed a Label inside the cell and centered in vertically and horizontal

enter image description here

Code:

private let reuseIdentifier = "Cell"

class MyViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        var layout: UICollectionViewFlowLayout {
            let layout = UICollectionViewFlowLayout()
            layout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
            layout.minimumLineSpacing = 0
            layout.minimumInteritemSpacing = 5
            layout.sectionInset = UIEdgeInsets(top: 20, left: 20, bottom: 0, right: 20)
            layout.sectionInsetReference = .fromContentInset
            return layout
        }
        
        collectionView.collectionViewLayout = layout
    }

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


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

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

    /*func collectionView(_ collectionView : UICollectionView,layout collectionViewLayout:UICollectionViewLayout,sizeForItemAt indexPath:IndexPath) -> CGSize {
        var width = view.frame.width
        return CGSize(width: collectionVw.frame.size.height, height: collectionVw.frame.size.height)
    }*/
}

Using different values for layout.minimumInteritemSpacing = 5 creates results I do not understand:

enter image description here

  • Why are the items 50 x 50px in size? I know that one can use ...sizeForItemAt to specify explicit dimensions. However, setting the size in IB should also work, shouldn't it? Why is the IB size of 200 x 200px ignored? Why 50x50, is this the default size or where is this specified? Solved in the answer by @Larme
  • I know that minimumInteritemSpacing does not set the explicit spacing but only a minimum. However, how is the value computed?
  • Why is the a spacing of 7.5px for a value of 5? Why result values 10-25 result all in the same a spacing of 26.5px?

So: How exactly are sizes and spacing computed here?

Andrei Herford
  • 17,570
  • 19
  • 91
  • 225

1 Answers1

1

You have multiple questions (not really recommended), I'll answer what I can do.

Why are the items 50 x 50px in size? I know that one can use ...sizeForItemAt to specify explicit dimensions. However, setting the size in IB should also work, shouldn't it? Why is the IB size of 200 x 200px ignored? Why 50x50, is this the default size or where is this specified?

You are doing:

collectionView.collectionViewLayout = layout

Where layout is newly created.
You aren't using the previous settings in InterfaceBuilder, you are overriding them by code.
And your created for layout, its itemSize hasn't been set. And from the doc, if not set, it's 50x50.

Why are the items aligned to the left for these values and distribued evenly of the complete width for value of 30?

Are you sure about that? Default Layout (meaning, not a inherited from UICollectionViewFlowLayout) will behave like paragraphs styling. I'll take the horizontal layout (same logic can be applied in vertical, but analogy with text paragraphs would be strange):

If you have multilines text, the first line would take as much width as possible, but the last line will not, keeping it "left" aligned.

For your spacing calculations, according to the doc of minimumInterItemSpacing:

For a vertically scrolling grid, this value represents the minimum spacing between items in the same row. For a horizontally scrolling grid, this value represents the minimum spacing between items in the same column. This spacing is used to compute how many items can fit in a single line, but after the number of items is determined, the actual spacing may possibly be adjusted upward.

But, I'm wondering, what would happen if you override viewDidLayoutSubview(), and call collectionView.collectionViewLayout?.invalidateLayout(); collectionView.collectionViewLayout?.prepareLayout().

Larme
  • 24,190
  • 6
  • 51
  • 81
  • Thanks for the detailed answer. You are absolutely right about the 50x50px default size. About the other questions: I am a 100% sure `UICollectionViewFlowLayout` is used and now subclass (just as in the code shown in the question) and it behaves as you can see in the image: "left aligned" for values up to 25, paragraph style for value 30. Why is this? About the calculation: I know the information from the docs you quoted. However, "...the actual spacing may possibly be adjusted" does not realy explain in detail how the spacing is computed, does it? – Andrei Herford May 21 '21 at 10:03
  • Do you have a Sample project? – Larme May 21 '21 at 10:06
  • Just prepared one, but how/where could I upload it? It is really jus a new project, replace the initial view controller in storyboard with a `UICollectionViewController`, and use the code shown in my question. – Andrei Herford May 21 '21 at 10:16
  • GitHub can be fine. Note that also if you rotate your simulator where you took the screenshot, does it take as you think the whole width (for your last sample?) – Larme May 21 '21 at 10:17
  • Rotation was a good hint: Spacing stays the same (does not use complete width in landscape). So it seems that that using "complete width" is just a coincidence for `minimumInteritemSpacing = 30`. However, the main question remains: "how exactly are spacings calculated" – Andrei Herford May 21 '21 at 10:25