Reputation: 1374
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:
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
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