Geen omschrijving

WaterfallFlowLayout.swift 4.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. //
  2. // WaterfallFlowLayout.swift
  3. // PaiAi
  4. //
  5. // Created by FFIB on 2017/11/13.
  6. // Copyright © 2017年 yb. All rights reserved.
  7. //
  8. import UIKit
  9. class WaterfallFlowLayout: UICollectionViewLayout {
  10. private var minColumn: Int = 0
  11. private var itemWidth: CGFloat = -1
  12. private var columnHeights = [CGFloat]()
  13. private var minColumnHeight: CGFloat = 0
  14. private(set) var configuration = WaterfallFlowConfiguration()
  15. private var attributesArr = [UICollectionViewLayoutAttributes]()
  16. override init() {
  17. super.init()
  18. }
  19. convenience init(configuration: WaterfallFlowConfiguration) {
  20. self.init()
  21. self.configuration = configuration
  22. }
  23. required init?(coder aDecoder: NSCoder) {
  24. super.init(coder: aDecoder)
  25. }
  26. override func prepare() {
  27. super.prepare()
  28. initialize()
  29. }
  30. override var collectionViewContentSize: CGSize {
  31. return calculateViewSize()
  32. }
  33. override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
  34. guard attributesArr.count <= indexPath.row else {
  35. return attributesArr[indexPath.row]
  36. }
  37. let itemX = calculateItemX()
  38. let itemY = calculateItemY()
  39. let itemHeight = calculateItemHeight(indexPath: indexPath)
  40. let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
  41. attributes.frame = CGRect(x: itemX, y: itemY, width: itemWidth, height: itemHeight)
  42. setMinColumn(h: itemHeight)
  43. return attributes
  44. }
  45. override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
  46. return attributesArr
  47. }
  48. func initialize() {
  49. guard let itemCount = collectionView?.numberOfItems(inSection: 0),
  50. itemCount != 0 else { return }
  51. let originIndex: Int
  52. if attributesArr.count >= itemCount || itemWidth == -1 {
  53. minColumn = 0
  54. originIndex = 0
  55. minColumnHeight = 0
  56. attributesArr.removeAll()
  57. calculateItemWidth()
  58. columnHeights = Array(repeating: 0, count: configuration.columnCount)
  59. } else {
  60. originIndex = attributesArr.count
  61. }
  62. for i in originIndex..<itemCount {
  63. guard let attributes = layoutAttributesForItem(at: IndexPath(row: i, section: 0))
  64. else { continue }
  65. attributesArr.append(attributes)
  66. }
  67. }
  68. func calculateViewSize() -> CGSize {
  69. guard let collectionView = collectionView,
  70. let maxH = columnHeights.max() else { return CGSize.zero }
  71. return CGSize(width: collectionView.bounds.width, height: maxH + configuration.rowSpace)
  72. }
  73. func calculateItemX() -> CGFloat {
  74. return CGFloat(minColumn) * itemWidth + CGFloat(minColumn + 1) * configuration.columnSpace
  75. }
  76. func calculateItemY() -> CGFloat {
  77. minColumnHeight += configuration.rowSpace
  78. return minColumnHeight
  79. }
  80. func calculateItemWidth() {
  81. let width = collectionView?.bounds.width ?? 0
  82. itemWidth = (width - configuration.columnSpace * (CGFloat(configuration.columnCount + 1))) / CGFloat(configuration.columnCount)
  83. }
  84. func calculateItemHeight(indexPath: IndexPath) -> CGFloat {
  85. guard let collectionView = collectionView,
  86. let delegate = collectionView.delegate as? UICollectionViewDelegateFlowLayout
  87. else { return 0 }
  88. let itemOriginSize = delegate.collectionView!(collectionView,
  89. layout: self,
  90. sizeForItemAt: indexPath)
  91. return itemWidth / itemOriginSize.width * itemOriginSize.height
  92. }
  93. func setMinColumn(h: CGFloat) {
  94. minColumnHeight += h
  95. columnHeights[minColumn] = minColumnHeight
  96. (minColumn, minColumnHeight) = columnHeights.enumerated().min(by: { $0.1 < $1.1 }) ?? (0, 0)
  97. }
  98. }