SAIToolboxInputViewLayout.swift 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. //
  2. // SAIToolboxInputViewLayout.swift
  3. // SAC
  4. //
  5. // Created by SAGESSE on 9/15/16.
  6. // Copyright © 2016-2017 SAGESSE. All rights reserved.
  7. //
  8. import UIKit
  9. @objc
  10. internal protocol SAIToolboxInputViewLayoutDelegate: UICollectionViewDelegate {
  11. @objc optional func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: SAIToolboxInputViewLayout, insetForSectionAt index: Int) -> UIEdgeInsets
  12. @objc optional func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: SAIToolboxInputViewLayout, numberOfRowsForSectionAt index: Int) -> Int
  13. @objc optional func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: SAIToolboxInputViewLayout, numberOfColumnsForSectionAt index: Int) -> Int
  14. }
  15. internal class SAIToolboxInputViewLayout: UICollectionViewLayout {
  16. func numberOfRows(in section: Int) -> Int {
  17. guard let collectionView = collectionView else {
  18. return 2
  19. }
  20. guard let delegate = collectionView.delegate as? SAIToolboxInputViewLayoutDelegate else {
  21. return 2
  22. }
  23. return delegate.collectionView?(collectionView, layout: self, numberOfRowsForSectionAt: section) ?? 2
  24. }
  25. func numberOfColumns(in section: Int) -> Int {
  26. guard let collectionView = collectionView else {
  27. return 4
  28. }
  29. guard let delegate = collectionView.delegate as? SAIToolboxInputViewLayoutDelegate else {
  30. return 4
  31. }
  32. return delegate.collectionView?(collectionView, layout: self, numberOfColumnsForSectionAt: section) ?? 4
  33. }
  34. func contentInset(in section: Int) -> UIEdgeInsets {
  35. guard let collectionView = collectionView else {
  36. return .zero
  37. }
  38. guard let delegate = collectionView.delegate as? SAIToolboxInputViewLayoutDelegate else {
  39. return .zero
  40. }
  41. return delegate.collectionView?(collectionView, layout: self, insetForSectionAt: section) ?? .zero
  42. }
  43. weak var delegate: SAIToolboxInputViewLayoutDelegate? {
  44. return collectionView?.delegate as? SAIToolboxInputViewLayoutDelegate
  45. }
  46. override var collectionViewContentSize: CGSize {
  47. let count = collectionView?.numberOfItems(inSection: 0) ?? 0
  48. let maxCount = numberOfRows(in: 0) * numberOfColumns(in: 0)
  49. let page = (count + (maxCount - 1)) / maxCount
  50. let frame = collectionView?.frame ?? CGRect.zero
  51. return CGSize(width: frame.width * CGFloat(page) - 1, height: 0)
  52. }
  53. override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
  54. if collectionView?.frame.width != newBounds.width {
  55. return true
  56. }
  57. return false
  58. }
  59. override func prepare() {
  60. super.prepare()
  61. _attributesCache = nil
  62. }
  63. override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
  64. if let attributes = _attributesCache {
  65. return attributes
  66. }
  67. var ats = [UICollectionViewLayoutAttributes]()
  68. // 生成
  69. let edg = contentInset(in: 0)
  70. let frame = collectionView?.bounds ?? .zero
  71. let count = collectionView?.numberOfItems(inSection: 0) ?? 0
  72. let width = frame.width - edg.left - edg.right
  73. let height = frame.height - edg.top - edg.bottom
  74. let irows = numberOfRows(in: 0)
  75. let icolumns = numberOfColumns(in: 0)
  76. let rows = CGFloat(irows)
  77. let columns = CGFloat(icolumns)
  78. let w: CGFloat = min(trunc((width - 8 * columns) / columns), 80)
  79. let h: CGFloat = min(trunc((height - 4 * rows) / rows), 80)
  80. let yg: CGFloat = (height / rows) - h
  81. let xg: CGFloat = (width / columns) - w
  82. // fill
  83. for i in 0 ..< count {
  84. // 计算。
  85. let r = CGFloat((i / icolumns) % irows)
  86. let c = CGFloat((i % icolumns))
  87. let idx = IndexPath(item: i, section: 0)
  88. let page = CGFloat(i / (irows * icolumns))
  89. let a = self.layoutAttributesForItem(at: idx) ?? UICollectionViewLayoutAttributes(forCellWith: idx)
  90. let x = edg.left + xg / 2 + c * (w + xg) + page * frame.width
  91. let y = edg.top + yg / 2 + r * (h + yg)
  92. a.frame = CGRect(x: x, y: y, width: w, height: h)
  93. ats.append(a)
  94. }
  95. _attributesCache = ats
  96. return ats
  97. }
  98. private var _defaultRows: Int = 2
  99. private var _defaultColumns: Int = 4
  100. private var _attributesCache: [UICollectionViewLayoutAttributes]?
  101. }