你是正確的,你需要繼承UICollectionViewLayout。 開始之前需要了解的基本知識是,您需要至少計算集合視圖中每個單元格的位置和大小。 UICollectionViewLayout只是提供該信息的結構化方式。你得到結構,但你必須自己提供一切。
有4種方法,你需要重寫:
- 準備
- 的invalidateLayout
- layoutAttributesForItemAtIndexPath
- layoutAttributesForElementsInRect
一個竅門是緩存中查找表的佈局屬性(字典):
var cachedItemAttributes = [IndexPath: UICollectionViewLayoutAttributes]()
在準備,你計算你的CollectionView每個indexPath佈局屬性:
override func prepare() {
super.prepare()
calculateAttributes()
}
在的invalidateLayout重置緩存佈局屬性,並重新計算它們:
override func invalidateLayout() {
super.invalidateLayout()
cachedItemAttributes = [:]
calculateAttributes()
}
在layoutAttributesForItemAtIndexPath您使用查找表返回正確的佈局屬性:
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
return cachedItemAttributes[indexPath]
}
在layoutAttributesForElementsInRect您篩選的查找表指定的矩形內的元素:
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
return cachedItemAttributes.filter { rect.intersects($0.value.frame) }.map { $0.value }
}
的最後一塊拼圖是實際計算佈局屬性。在這裏,我將只提供僞代碼:
func calculateAttributes() {
// For each indexpath (you can get this from the collectionView property using numberOfSections and numberOfItems:inSection)
// calculate the frame, i.e the origin point and size of each cell in your collectionView and set it with UICollectionViewLayoutAttributes.frame
// There are many other properties on UICollectionViewLayoutAttributes that you can tweak for your layout, but frame is a good starting point from which you can start experimenting.
// Add the layout attributes to the lookup table
// end loop
}
要回答你的問題,這裏是僞代碼來計算每個單元的位置:
// If width of cell + current width of row + spacing, insets and margins exceeds the available width
// move to next row.
// else
// cell origin.x = current width of row + interitem spacing
// cell origin.y = number of rows * (row height + spacing)
// endif
如果您需要您的自定義佈局可配置,那麼如果可用的簽名足夠,則使用UICollectionViewDelegateFlowLayout;或者定義從UICollectionViewDelegateFlowLayout或UICollectionViewDelegate繼承的自己。因爲你的協議是從UICollectionViewDelegateFlowLayout繼承而來的,UICollectionViewDelegateFlowLayout本身是從UICollectionViewDelegate繼承的,所以你可以直接在你的viewcontroller中將它設置爲collectionView委託。在您的自定義集合視圖佈局中,您只需將來自UICollectionViewDelegate的委託轉換爲您的自定義協議即可使用它。請記住處理投射失敗或協議方法未由代表實施的情況。
只使用一個部分將產生所需的結果。你有什麼理由需要使用多個部分? – bsmith11
我正在使用一個NSFetchedResultsController,它有一個定義的sectionNameKeyPath,將結果分解成這些部分。此控制器和緩存的結果在此collectionView和另一個顯示分節符的tableView之間共享 - 因此需要設置sectionNameKeyPath。我意識到我可以做一些時髦的NSIndexPath切換,使其在一個部分爲collectionView工作,但我認爲最乾淨的解決方案是調整流佈局。 –
我不相信有一個乾淨的方式來實現你想要的,而不需要繼承'UICollectionViewLayout'。如果你使用了兩個單獨的NSFetchedResultsController呢? – bsmith11