DJB
DJB

Reputation: 267

Custom spacing between only some cells in a UICollectionView

I am attempting to create a UICollectionView which is horizontal scrolling and a single row. Cells can be added dynamically to the end of the collection. I want the behaviour to be that when a certain number of cells are in the UICollectionView and a new one is added, the first x number of cells will squish their spacing whilst remaining the same size. Ideally I want the first x cells to actually overlap each other somewhat (would look like a stack) to conserve maximum space. The remaining cells in the collection after x will display with the normal spacing between them.

A visual:

( ) ( ) ( ) ( ) ( ) normal layout where ( ) is an item

would become as such when two more items are added:

((((( ) ( ) ( )

or ( ))))) ( ) ( ) if the first item was at the top of the stack (I don't mind which right now, just the stack is important)

Can anyone offer any help and advice on how this can be achieved?

Upvotes: 0

Views: 58

Answers (2)

DJB
DJB

Reputation: 267

For anyone interested, I achieved this by subclassing UICollectionViewFlowLayout and overriding as below. Bare in mind I used an additional cell at the end of the collection as an addCell button, so this implementation accounts for that and will do the rearrangement after 5 real items have been added and you go to add a 6th. My cells had a width of 50 with a minimum spacing of 10 when normally laid out.

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    guard collectionView!.numberOfItems(inSection: 0) > 6 else {
        return super.layoutAttributesForElements(in: rect)
    }

    let layouts = super.layoutAttributesForElements(in: rect)?.map { $0.copy() as! UICollectionViewLayoutAttributes }
    for (index, layout) in layouts!.enumerated() {
        var frame = layout.frame
        frame.origin.x = frame.origin.x - (35.0 * CGFloat(index < 5 ? index : (index - (index - 4))))
        layout.frame = frame
    }

    return layouts
}

Upvotes: 1

matt
matt

Reputation: 535556

You can achieve any positioning you like, because you get to write the UICollectionViewLayout that tells the collection view how to position its items.

A flow layout, by default, will not do what you are describing. It simply lays out all the items in each row with the same spacing, based on the collection view content width and the minimum item spacing you supply. But if you subclass UICollectionViewFlowLayout, you can probably modify the behavior of the flow layout to do what you are describing. Thus, you would not need to write the layout object entirely from scratch.

However, for maximum flexibility, writing the layout object entirely from scratch is exactly what you would do. It really isn't all that hard. Apple has many examples and of course there are many tutorial examples out there as well.

Upvotes: 0

Related Questions