DonBaron
DonBaron

Reputation: 1374

UICollectionView / FlowLayout

I'm facing a challenge when using UICollectionView and a related Layout. I'm trying to create a vertical UICollectionView with two columns, where as the cells in the left and right columns are positioned as displayed in the picture:

enter image description here

I do manage without problems to create the two columns but struggle finding the correct settings in my Layout in order to have the right column be offset by half the height of one cell. Note, all cells have the same calculated dimension based on the width of the screen (minus the spacing)...

Every cell in my data array has got a position index, I can thus easily find out whether a cell is positioned right or left based base on it (odd / even)

Any help is gladly appreciated

Upvotes: 1

Views: 780

Answers (1)

EmilioPelaez
EmilioPelaez

Reputation: 19932

Here's how I would implement a subclass of UICollectionViewFlowLayout to achieve what you want.

class OffsetFlowLayout: UICollectionViewFlowLayout {
    var verticalOffset: CGFloat = 0

    override func prepare() {
        super.prepare()
        verticalOffset = 100 // Calculate offset here
    }

    override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        guard let attributes = super.layoutAttributesForItem(at: indexPath) else { return nil }
        guard remainder(Double(indexPath.row), 2) != 0 else { return attributes }
        //  For each item in the right column, offset the y value of it's origin
        attributes.frame.origin.y += verticalOffset
        return attributes
    }
}

As you can see, on our implementation of layoutAttributesForItem the first thing we do is to call super and store the value it returns. Then we check the index and if we are on the left column, we return what super gave us, which would be the "default" value.

If we're on the right column, we modify the attributes object to move the frame of the cell by the offset we want, and then return that one.

NOTE: I haven't tested this. There's a chance the UICollectionViewFlowLayout uses the previous cells to layout the next cells, in which case you would only need to modify the first element in the right column, just change guard remainder(Double(indexPath.row), 2) != 0 else { return attributes } to guard indexPath.row == 1 else { return attributes }

Upvotes: 1

Related Questions