Bugrym
Bugrym

Reputation: 85

Collection view items equal spacing layout

I have no experience in collection view layout and I decided to ask your advices. I faced with the next problem. I have a simple collection view with custom cell. Cell has only label, which has left and right constraints equal to 16. So the width of cell depends on content of label. And I have no clue why items have so strange spacings. I set spacings in the storyboard - 12 points left and right spacings. Actual result: enter image description here I wanna get something like this: enter image description here So in which direction should I move? Thanks for your answers.

UPDATE: Strange behaviour occurs on iPhones running iOS 12..<13.0

enter image description here

Upvotes: 0

Views: 93

Answers (1)

Tarun Tyagi
Tarun Tyagi

Reputation: 10112

What you are seeing is the default behavior for collectionView layout.

You need to subclass UICollectionViewFlowLayout to get this behavior.

import UIKit

class LeftAlignCellCollectionFlowLayout: UICollectionViewFlowLayout {
    
    private(set) var cellHeight: CGFloat = 36
    init(cellHeight: CGFloat) {
        super.init()
        self.cellHeight = cellHeight
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }
    
    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        guard let attributes = super.layoutAttributesForElements(in: rect) else { return nil }
        guard let collectionView = self.collectionView else { return nil }
        
        self.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
        
        var newAttributes = attributes
        var leftMargin = self.sectionInset.left
        var maxY: CGFloat = -1.0
        
        let availableWidth: CGFloat = collectionView.frame.width
        let layout = collectionView.collectionViewLayout
        
        for attribute in attributes {
            if let cellAttribute = layout.layoutAttributesForItem(at: attribute.indexPath) {
                if cellAttribute.frame.width > availableWidth {
                    cellAttribute.frame.origin.x = 0
                    cellAttribute.frame.size = CGSize(width: availableWidth, height: cellHeight)
                }
                else {
                    if cellAttribute.frame.origin.y >= maxY {
                        leftMargin = self.sectionInset.left
                    }
                    
                    var frame = cellAttribute.frame
                    frame.origin.x = leftMargin
                    frame.size.height = cellHeight
                    cellAttribute.frame = frame
                    
                    leftMargin += cellAttribute.frame.width + self.minimumInteritemSpacing
                    maxY = max(cellAttribute.frame.maxY , maxY)
                }
                
                newAttributes.append(cellAttribute)
            }
        }
        
        return newAttributes
    }
}

Now you can use above layout like this.

let flowLayout = LeftAlignCellCollectionFlowLayout(cellHeight: 40)
flowLayout.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
flowLayout.minimumInteritemSpacing = 10
flowLayout.minimumLineSpacing = 10
collectionView.collectionViewLayout = flowLayout

Upvotes: 1

Related Questions