暂无描述

WaterfallFlowLayout.swift 4.2KB

    // // WaterfallFlowLayout.swift // PaiAi // // Created by FFIB on 2017/11/13. // Copyright © 2017年 yb. All rights reserved. // import UIKit public final class WaterfallFlowLayout: UICollectionViewLayout { private var minColumn: Int = 0 private var itemWidth: CGFloat = -1 private var columnHeights = [CGFloat]() private var minColumnHeight: CGFloat = 0 private(set) var configuration = WaterfallFlowConfiguration() private var attributesArr = [UICollectionViewLayoutAttributes]() override public init() { super.init() } convenience init(configuration: WaterfallFlowConfiguration) { self.init() self.configuration = configuration } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } override public func prepare() { super.prepare() initialize() } override public var collectionViewContentSize: CGSize { return calculateViewSize() } override public func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { guard attributesArr.count <= indexPath.row else { return attributesArr[indexPath.row] } let itemX = calculateItemX() let itemY = calculateItemY() let itemHeight = calculateItemHeight(indexPath: indexPath) let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath) attributes.frame = CGRect(x: itemX, y: itemY, width: itemWidth, height: itemHeight) setMinColumn(h: itemHeight) return attributes } override public func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { return attributesArr } fileprivate func initialize() { guard collectionView?.numberOfSections == 1, let itemCount = collectionView?.numberOfItems(inSection: 0), itemCount != 0 else { return } let originIndex: Int if attributesArr.count >= itemCount || itemWidth == -1 { minColumn = 0 originIndex = 0 minColumnHeight = 0 attributesArr.removeAll() calculateItemWidth() columnHeights = Array(repeating: 0, count: configuration.columnCount) } else { originIndex = attributesArr.count } for i in originIndex..<itemCount { guard let attributes = layoutAttributesForItem(at: IndexPath(row: i, section: 0)) else { continue } attributesArr.append(attributes) } } fileprivate func calculateViewSize() -> CGSize { guard let collectionView = collectionView, let maxH = columnHeights.max() else { return CGSize.zero } return CGSize(width: collectionView.bounds.width, height: maxH + configuration.rowSpace) } fileprivate func calculateItemX() -> CGFloat { return CGFloat(minColumn) * itemWidth + CGFloat(minColumn + 1) * configuration.columnSpace } fileprivate func calculateItemY() -> CGFloat { minColumnHeight += configuration.rowSpace return minColumnHeight } fileprivate func calculateItemWidth() { let width = collectionView?.bounds.width ?? 0 itemWidth = (width - configuration.columnSpace * (CGFloat(configuration.columnCount + 1))) / CGFloat(configuration.columnCount) } fileprivate func calculateItemHeight(indexPath: IndexPath) -> CGFloat { guard let collectionView = collectionView, let delegate = collectionView.delegate as? UICollectionViewDelegateFlowLayout else { return 0 } let itemOriginSize = delegate.collectionView!(collectionView, layout: self, sizeForItemAt: indexPath) return itemWidth / itemOriginSize.width * itemOriginSize.height } fileprivate func setMinColumn(h: CGFloat) { minColumnHeight += h columnHeights[minColumn] = minColumnHeight (minColumn, minColumnHeight) = columnHeights.enumerated().min(by: { $0.1 < $1.1 }) ?? (0, 0) } }