和上一篇自定義的瀑布流同樣,自定義瀑布流也是須要實現那個幾個方法bash
// 生成每一個視圖的佈局屬性(頭尾視圖和cell的佈局屬性) override func prepare() // 返回滾動區域的大小,當你的UICollectionView 不滾動的狀況下能夠檢查這個方法 override var collectionViewContentSize: CGSize{} // 返回該區域內的佈局屬性 override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? // 返回 indexpath 位置上的 cell 對應的佈局屬性 override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? 複製代碼
最關鍵的地方是在markdown
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes?
複製代碼
這個方法, 須要判斷這個 item 的 width + x 是否超過了最大的寬度, 根據這個要換行app
具體的代碼以下ide
import UIKit protocol UICollectionViewCategoryLayoutDelegate { // require /// 返回每一個item的Size func categoryLayout(_ categoryLayout:UICollectionViewCategoryLayout, sizeForItemAt indexPath:IndexPath) -> CGSize // optional func categoryLayout(_ categoryLayout:UICollectionViewCategoryLayout, columnMarginAt indexPath:IndexPath) -> CGFloat /// 行間距 func categoryLayout(_ categoryLayout:UICollectionViewCategoryLayout, rowMarginAt indexPath:IndexPath) -> CGFloat /// 列間距 func categoryLayout(_ categoryLayout:UICollectionViewCategoryLayout, edgInsetAt indexPath:IndexPath) -> UIEdgeInsets /// head的frame func categoryLayout(_ categoryLayout:UICollectionViewCategoryLayout, sizeForHeaderViewIn section:Int) -> CGSize /// foot的frame func categoryLayout(_ categoryLayout:UICollectionViewCategoryLayout, sizeForFooterViewIn section:Int) -> CGSize } extension UICollectionViewCategoryLayoutDelegate{ /// 返回列間距 默認是 10 func categoryLayout(_ categoryLayout:UICollectionViewCategoryLayout, columnMarginAt indexPath:IndexPath) -> CGFloat { return 10 } /// 返回行間距 默認是10 func categoryLayout(_ categoryLayout:UICollectionViewCategoryLayout, rowMarginAt indexPath:IndexPath) -> CGFloat{ return 10 } /// 返回每一個 section 的 UIEdgeInsets func categoryLayout(_ categoryLayout:UICollectionViewCategoryLayout, edgInsetAt indexPath:IndexPath) -> UIEdgeInsets{ return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) } /// 返回透視圖的size func categoryLayout(_ categoryLayout:UICollectionViewCategoryLayout, sizeForHeaderViewIn section:Int) -> CGSize{ return .zero } /// 返回尾視圖的size func categoryLayout(_ categoryLayout:UICollectionViewCategoryLayout, sizeForFooterViewIn section:Int) -> CGSize{ return .zero } } class UICollectionViewCategoryLayout: UICollectionViewLayout { /// 存儲最大的高度 var maxHeight:CGFloat = 0.0 var deleagte:UICollectionViewCategoryLayoutDelegate! /// 存放當前 Rect 中的全部 佈局屬性 lazy var attriArray:[UICollectionViewLayoutAttributes] = [] /// 記錄上個cell的 最大 X 值 x + width var lastMaxX:CGFloat = 0.0 /// 上個cell的 Y值 var lastMaxY:CGFloat = 0.0 override func prepare() { super.prepare() self.attriArray.removeAll() self.maxHeight = 0.0 self.lastMaxX = 0.0 self.lastMaxY = 0.0 if let collectionView = self.collectionView { let sectionCount = collectionView.numberOfSections for section in 0..<sectionCount{ self.lastMaxX = 0.0 // header let headerAttr = self.layoutAttributesForSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, at: IndexPath.init(item: 0, section: section)) if let headerAttr = headerAttr { self.attriArray.append(headerAttr) } // item let rowCount = collectionView.numberOfItems(inSection: section) for item in 0..<rowCount{ let itemAttri = self.layoutAttributesForItem(at: IndexPath.init(item: item, section: section)) if let itemAttri = itemAttri{ self.attriArray.append(itemAttri) } } // footer let footerAttri = self.layoutAttributesForSupplementaryView(ofKind:UICollectionView.elementKindSectionFooter, at: IndexPath.init(item: 0, section: section)) if let footerAttri = footerAttri { self.attriArray.append(footerAttri) } } } } override var collectionViewContentSize: CGSize{ return CGSize(width: 0, height: self.maxHeight) } override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { return self.attriArray } override func layoutAttributesForSupplementaryView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { var attri:UICollectionViewLayoutAttributes! if elementKind == UICollectionView.elementKindSectionHeader { attri = UICollectionViewLayoutAttributes.init(forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, with: indexPath) attri.frame = self.headerViewFrame(indexPath: indexPath) }else{ attri = UICollectionViewLayoutAttributes.init(forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, with: indexPath) attri.frame = self.footerViewFrame(indexPath: indexPath) } return attri } func headerViewFrame(indexPath:IndexPath) -> CGRect { let edgInset = self.deleagte.categoryLayout(self, edgInsetAt: indexPath) let size = self.deleagte.categoryLayout(self, sizeForHeaderViewIn: indexPath.section) let rwoMargin = self.deleagte.categoryLayout(self, rowMarginAt: indexPath) let x:CGFloat = 0.0 let y = self.maxHeight == 0.0 ? edgInset.top : self.maxHeight self.maxHeight = self.maxHeight + size.height + rwoMargin self.lastMaxY = self.maxHeight return CGRect(x: x, y: y, width: size.width, height: size.height) } func footerViewFrame(indexPath:IndexPath) -> CGRect { let edgInset = self.deleagte.categoryLayout(self, edgInsetAt: indexPath) let size = self.deleagte.categoryLayout(self, sizeForFooterViewIn: indexPath.section) let rwoMargin = self.deleagte.categoryLayout(self, rowMarginAt: indexPath) let x:CGFloat = 0.0 let y = self.maxHeight == 0.0 ? edgInset.top : self.maxHeight + rwoMargin self.maxHeight = self.maxHeight + size.height self.lastMaxY = self.maxHeight return CGRect(x: x, y: y, width: size.width, height: size.height) } override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { let attr = UICollectionViewLayoutAttributes.init(forCellWith: indexPath) let width = self.collectionView!.frame.size.width let edgInset = self.deleagte.categoryLayout(self, edgInsetAt: indexPath) let size = self.deleagte.categoryLayout(self, sizeForItemAt: indexPath) let columMarigin = self.deleagte.categoryLayout(self, columnMarginAt: indexPath) let rowMargin = self.deleagte.categoryLayout(self, rowMarginAt: indexPath) var x:CGFloat = 0.0 if self.maxHeight == 0.0 { self.lastMaxY = edgInset.top } // 表示行的最開始 if self.lastMaxX >= edgInset.left { x = self.lastMaxX + columMarigin self.lastMaxX = x + size.width // 換行顯示了 if x + size.width + edgInset.right > width { x = edgInset.left // 換行 self.lastMaxX = edgInset.left + size.width self.lastMaxY = self.lastMaxY + size.height + rowMargin } }else{ // 有可能存在一個 標籤太長, 一整行都顯示不下去 x = edgInset.left self.lastMaxX = edgInset.left + size.width } self.maxHeight = self.lastMaxY + size.height + edgInset.bottom attr.frame = CGRect(x: x, y: self.lastMaxY, width: size.width, height: size.height) return attr } } 複製代碼