Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Placing two sections next to each other in a UICollectionView

I have a CollectionView with 6 sections.

The first sections are organised as rows. Section 2 & 3 is where things get difficult. I need to place two sections right next to each other.

[................Section 1..............] // one section with a couple of rows
[... Section 2...][...Section 3...] // two sections beneath the first

I can't divide the second section in two columns because those are different populated with different cells.
Knowing that the flow layout always fills up one section from bounds to bounds, I could only fake such an effect by placing two cells next to each other, which is fine but I add cells and I can only place one beneath the other with an integer which increments each time I create a new cell in cellForItemAtIndexPath: and use it to multiply it by the cell's height.

The only problem I face then is when I reuse some cells the integer variable hack doesn't work anymore.

So is there a better way to, besides a custom layout, which might not do the trick either, to place two sections next to each other?

thanks in advance

like image 470
maxlxb Avatar asked Apr 29 '15 13:04

maxlxb


1 Answers

You don't necessarily have to write a custom layout, you can actually just subclass UICollectionViewFlowLayout and override a few key methods that determine frame positioning, namely layoutAttributesForElementsInRect:/ layoutAttributesForItemAtIndexPath: where you can check the section and determine positions.

The code itself would probably be relatively simple, something along the lines of:

if indexPath.section == 0 {
    attributes.frame = CGRect(x: 0, y: 0, width: fullWidth, height: someHeight)
} else {
    // Section 2 which is indexed at 1, set the frame
    // to half the width and x to 0
    if indexPath.section %2 != 0 {
        attributes.frame = CGRect(x: 0, y: someYCounter, width: halfWidth, height, someHeight)
    } else {
        attributes.frame = CGRect(x: halfWidth, y: someYCounter, width: halfWidth, height, someHeight)
    }
}

Obviously this is psuedo-code and I haven't run this through a compiler but the essential steps are:

  • have a guard statement that ensures the existence of collection view so you can define the following variables: halfWidth and fullWidth (to be used when laying out later)
  • keep a running counter of your y position
  • check the section index and position appropriately

The best way to go about this is to override prepare and calculate an array of layout attributes (and store that as an instance variable). Then in layoutAttributesForItemAtIndexPath: and the like, just return the object at the index in that array (or if the index is for some reason out of bounds, return super.layoutAttributesForItem(at: indexPath).

That is the beauty of UICollectionViewFlowLayout, most of the heavy lifting is done for you and you can subclass a few simple methods to get the desired behavior. The alternative is a full blown custom layout which, in my opinion, rarely justified unless you have some crazy behavior in which case you should be having conversations with your designers about the complexity of what they make.

like image 142
barndog Avatar answered Oct 10 '22 15:10

barndog