import UIKit
extension UICollectionViewLayoutAttributes {
func leftAlignFrame(_ sectionInset:UIEdgeInsets) {
var frame = self.frame
frame.origin.x = sectionInset.left
self.frame = frame
}
}
class UICollectionViewLeftAlignedLayout: UICollectionViewFlowLayout {
override init() {
super.init()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let attributesToReturn = super.layoutAttributesForElements(in: rect)!
var attributesCopy = [UICollectionViewLayoutAttributes]()
for attributes in attributesToReturn {
if nil == attributes.representedElementKind {
let itemAttributesCopy = attributes.copy() as! UICollectionViewLayoutAttributes
let indexPath = itemAttributesCopy.indexPath
itemAttributesCopy.frame = self.layoutAttributesForItem(at: indexPath)!.frame
attributesCopy.append(itemAttributesCopy)
}else{
attributesCopy.append(attributes)
}
}
return attributesCopy
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
let currentItemAttributes = super.layoutAttributesForItem(at: indexPath)?.copy() as! UICollectionViewLayoutAttributes
let sectionInset = self.evaluatedSectionInset(indexPath.section)
let isFirstItemInSection = indexPath.item == 0
let layoutWidth: CGFloat = self.collectionView!.frame.width - sectionInset.left - sectionInset.right
if isFirstItemInSection {
currentItemAttributes.leftAlignFrame(sectionInset)
return currentItemAttributes
}
let previousIndexPath = IndexPath(item: indexPath.item - 1, section: indexPath.section)
let previousFrame = self.layoutAttributesForItem(at: previousIndexPath)!.frame
let previousFrameRightPoint: CGFloat = previousFrame.origin.x + previousFrame.size.width
let currentFrame = currentItemAttributes.frame
let strecthedCurrentFrame = CGRect(x: sectionInset.left, y: currentFrame.origin.y, width: layoutWidth, height: currentFrame.size.height)
let isFirstItemInRow = !previousFrame.intersects(strecthedCurrentFrame)
if isFirstItemInRow {
currentItemAttributes.leftAlignFrame(sectionInset)
return currentItemAttributes
}
var frame = currentItemAttributes.frame
frame.origin.x = previousFrameRightPoint + self.evaluatedMinimumInteritemSpacing(indexPath.item)
currentItemAttributes.frame = frame
return currentItemAttributes
}
fileprivate func evaluatedMinimumInteritemSpacing(_ ItemAtIndex:Int) -> CGFloat {
if let delete = self.collectionView?.delegate {
weak var delegate = (delete as! UICollectionViewDelegateFlowLayout)
if delegate!.responds(to: #selector(UICollectionViewDelegateFlowLayout.collectionView(_:layout:minimumInteritemSpacingForSectionAt:))) {
let mini = delegate?.collectionView!(self.collectionView!, layout: self, minimumInteritemSpacingForSectionAt: ItemAtIndex)
if mini != nil {
return mini!
}
}
}
return self.minimumInteritemSpacing
}
fileprivate func evaluatedSectionInset(_ itemAtIndex:Int) -> UIEdgeInsets {
if let delete = self.collectionView?.delegate {
weak var delegate = (delete as! UICollectionViewDelegateFlowLayout)
if delegate!.responds(to: #selector(UICollectionViewDelegateFlowLayout.collectionView(_:layout:insetForSectionAt:))) {
let sectionInset = delegate?.collectionView!(self.collectionView!, layout: self, insetForSectionAt: itemAtIndex)
if sectionInset != nil {
return sectionInset!
}
}
}
return self.sectionInset
}
}