iosiphoneiglistkit

How to make custom IGListSectionController


I'm exploring IGListKit and I'm trying to achieve this with a IGListSectionController subclass:

enter image description here

Basically, each colored area is one UICollectionViewCell. I already done something that doesn't have the green area. But, what I want is the layout in the example above. How do I do this?


Solution

  • I found the answer and it was actually pretty simple. So, (like in UICollectionView) it must be set with a custom UICollectionViewLayout. So I have something like this:

    let collectionView:IGListCollectionView = {
        let layout = MyCustomLayout()
        let view = IGListCollectionView(frame: .zero, collectionViewLayout: layout)
        return view
    }() 
    

    Here's what my custom layout looks like:

    protocol MyCustomLayoutDelegate {
        func heightForItem(inCollectionView: UICollectionView, at position: Int) -> CGFloat
    }
    
    class MyCustomLayout: UICollectionViewLayout, MyCustomLayoutDelegate {
    
        var delegate:MyCustomLayoutDelegate?
    
        private var cache = [UICollectionViewLayoutAttributes]()
    
        private var aHeight:CGFloat = 0
    
        private var contentWidth:CGFloat {
            return collectionView!.bounds.width
        }
    
        override func prepare() {
    
            if cache.isEmpty {
    
                var yOffset:CGFloat = 0
    
                for section in 0 ..< collectionView!.numberOfSections {
                    let contentHeight = (delegate ?? self).heightForItem(inCollectionView: collectionView!, at: section)
                    let leftAreaWidth = contentHeight - 1
                    let topAreaHeight:CGFloat = 20.0
                    let bottomAreaHeight = contentHeight - topAreaHeight - 1
                    let bottomAreaWidth = contentWidth - leftAreaWidth
    
                    let leftAreaIndexPath = IndexPath(item: 0, section: section)
                    let topAreaIndexPath = IndexPath(item: 1, section: section)
                    let bottomAreaIndexPath = IndexPath(item: 2, section: section)
    
                    let leftAreaFrame = CGRect(x: 0, y: yOffset, width: leftAreaWidth, height: leftAreaWidth)
                    let topAreaFrame = CGRect(x: leftAreaWidth, y: yOffset, width: bottomAreaWidth, height: topAreaHeight)
                    let bottomAreaFrame = CGRect(x: leftAreaWidth, y: yOffset + topAreaHeight, width: bottomAreaWidth, height: bottomAreaHeight)
    
                    let leftAreaAttributes = UICollectionViewLayoutAttributes(forCellWith: leftAreaIndexPath)
                leftAreaAttributes.frame = leftAreaFrame
                cache.append(leftAreaAttributes)
    
                    let topAreaAttributes = UICollectionViewLayoutAttributes(forCellWith: topAreaIndexPath)
                topAreaAttributes.frame = topAreaFrame
                cache.append(topAreaAttributes)
    
                    let bottomAreaAttributes = UICollectionViewLayoutAttributes(forCellWith: bottomAreaIndexPath)
                bottomAreaAttributes.frame = bottomAreaFrame
                cache.append(bottomAreaAttributes)
    
                    yOffset += contentHeight
                }
    
                aHeight = yOffset
            }
        }
    
        override var collectionViewContentSize: CGSize {
            return CGSize(width: contentWidth, height: aHeight)
        }
    
        override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    
            return cache.filter {
                $0.frame.intersects(rect)
            }
        }
    
        override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
    
            return cache.first {
                $0.indexPath == indexPath
            }
    
        }
    
        override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
    
            if let oldWidth = collectionView?.bounds.width {
                return oldWidth != newBounds.width
            }
    
            return false
        }
    
        override func invalidateLayout() {
            super.invalidateLayout()
    
            cache = []
            aHeight = 0
        }
    
        //Delegate
        internal func heightForItem(inCollectionView: UICollectionView, at postion: Int) -> CGFloat {
            return 0
        }
    }