2

I'm trying to create a horizontal UICollectionView with possibility to align part of cells to the left side and other part to the right. Between right and left cells should be empty space. Is it possible using UICollectionView and UICollectionViewFlowLayout?

I tried this version of UICollectionViewFlowLayout but it doesn't work properly. I'm trying to understand how to calculate offset dynamically.

class LeftRightAlignedCollectionViewFlowLayout: UICollectionViewFlowLayout {
    
    var offset: CGFloat = 30
    
    fileprivate var layoutAttributes = [UICollectionViewLayoutAttributes]()
    fileprivate var contentSize = CGSize.zero
    
    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        guard let superAttributes = super.layoutAttributesForElements(in: rect) else { return nil }
        var attributes = superAttributes
        let centerX = collectionView!.contentOffset.x + collectionView!.bounds.width / 2.0
        
        for attribute in attributes {
            let distance = abs(attribute.center.x - centerX)
            let offset = min(abs(distance), self.offset)
            let factor = (self.offset - offset) / self.offset
            let translation = factor * attribute.size.width / 2
            attribute.center.x += distance < self.offset ? (attribute.center.x < centerX ? -translation : translation) : 0
        }
        return attributes
    }
    
    override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
        return true
    }
}

1 Answers1

0

Please try this code in the layoutAttributesForElements function:

guard let superAttributes = super.layoutAttributesForElements(in: rect) else { return nil }
var attributes = superAttributes
let centerX = collectionView!.contentOffset.x + collectionView!.bounds.width / 2.0

// Separate the attributes for left and right cells
var leftAttributes: [UICollectionViewLayoutAttributes] = []
var rightAttributes: [UICollectionViewLayoutAttributes] = []
for attribute in attributes {
    if attribute.center.x < centerX {
        leftAttributes.append(attribute)
    } else {
        rightAttributes.append(attribute)
    }
}

// Calculate the total width of the left and right cells
let leftWidth = leftAttributes.reduce(0) { $0 + $1.size.width }
let rightWidth = rightAttributes.reduce(0) { $0 + $1.size.width }

// Adjust the position of the left cells
var xPosition: CGFloat = 0
for attribute in leftAttributes {
    let frame = attribute.frame
    attribute.frame = CGRect(x: xPosition, y: frame.origin.y, width: frame.size.width, height: frame.size.height)
    xPosition += frame.size.width
}

// Calculate the offset for the right cells and adjust their position
let offset = (collectionViewContentSize.width - leftWidth - rightWidth) / 2
xPosition = collectionViewContentSize.width - rightWidth
for attribute in rightAttributes {
    let frame = attribute.frame
    attribute.frame = CGRect(x: xPosition + offset, y: frame.origin.y, width: frame.size.width, height: frame.size.height)
    xPosition += frame.size.width
}

return attributes
Venus
  • 453
  • 2
  • 9