I have a "cumulative" lookup array for a custom collection view layout.
The idea is that I have an array of rectangles, each with an index. The index is not unique, and is monotonically increasing. I need to create a lookup table, such that given a cell index, it returns the accumulated height of all rects lower than that index.
Here is my implementation. I am wondering if it can be improved (for maintainability) using functional programming, or an established algorithm. Nested loops always raises a flag for me:
var offsets: [CGFloat] = [0]
while metas.count > 0 {
// meta is a struct that holds an index and rect.
let meta = metas.removeAtIndex(0)
while offsets.count <= meta.index {
// copy the previous value, to maintain accumulation
offsets.append(offsets[offsets.count - 1])
}
offsets[meta.index] += meta.rect.height
}
let cellCount = self.collectionView?.numberOfItemsInSection(0) ?? 0
// need to pad the array at the end
while offsets.count < cellCount {
offsets.append(offsets[offsets.count - 1])
}
Background:
I am implementing my own collection view layout. It has sticky headers, custom supplementary views, and other customizations. To implement a custom layout, 4 critical methods must be implemented:
override func collectionViewContentSize() -> CGSize {
let width = self.collectionView?.bounds.width ?? 0
let height = allLayoutAttributes.last?.frame.maxY ?? 0
return CGSize(width: width, height: height)
}
override func layoutAttributesForElementsInRect(rect: CGRect) -> [AnyObject]? {
return allLayoutAttributes.filter {
$0.frame.intersects(rect)
}
}
override func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes! {
return cellLayoutAttributes[indexPath.item]
}
override func layoutAttributesForSupplementaryViewOfKind(elementKind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes! {
return supplementaryLayoutAttributes[indexPath.item]
}
As you can see from the implementation, I am preferring computing everything ahead of time, and then just returning the attributes when the methods are called. Now, since supplementary views are inlined with the cells, here is how I was computing things:
- Since cell height is fixed, calculate the position of all supplementary view. I know all their offsets, but they vary in height.
- cells need to be offset by all the cell heights before them + supplementary heights.
The approach I took above was to compute supplementary view in isolation, get it over with, create a lookup table for the offsets they represent, then iterate the cells and apply the offset as required.
UICollectionViewLayout
directly. – Mazyod Nov 8 '14 at 10:55