//CollectionView會在初次布局時首先調用該方法
//CollectionView會在布局失效后、重新查詢布局之前調用此方法
//子類中必須重寫該方法并調用超類的方法
- (void)prepareLayout;
//子類必須重寫此方法。
//并使用它來返回CollectionView視圖內容的寬高,
//這個值代表的是所有的內容的寬高,并不是當前可見的部分。
//CollectionView將會使用該值配置內容的大小來促進滾動。
- (CGRect)collectionViewContentSize;
// UICollectionView 調用以下四個方法來確定布局信息
- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect; // return an array layout attributes instances for all the views in the given rect
- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath;
- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath;
- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForDecorationViewOfKind:(NSString*)elementKind atIndexPath:(NSIndexPath *)indexPath;
//當Bounds改變時,返回YES使CollectionView重新查詢幾何信息的布局
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds;
自定義UICollectionView,主要會用到以下幾個方法:
- (void)prepareLayout;
第一次加載layout、刷新layout、以及- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds;這個方法返回yes時,會調用。這是蘋果官方的說明The collection view calls -prepareLayout once at its first layout as the first message to the layout instance. The collection view calls -prepareLayout again after layout is invalidated and before requerying the layout information. Subclasses should always call super if they override。實現(xiàn)該方法后應該調用[super prepareLayout]保證初始化正確。該方法用來準備一些布局所需要的信息。該方法和init方法相似,但該方法可能會被調用多次,所以一些不固定的計算(比如該計算和collectionView的尺寸相關),最好放在這里,以保證collectionView發(fā)生變化時,自定義CollectionView能做出正確的反應。
- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect;
該方法用來返回rect范圍內的 cell supplementary 以及 decoration的布局屬性layoutAttributes(這里保存著她們的尺寸,位置,indexPath等等),如果你的布局都在一個屏幕內 活著 沒有復雜的計算,我覺得這里可以返回全部的屬性數(shù)組,如果涉及到復雜計算,應該進行判斷,返回區(qū)域內的屬性數(shù)組,有時候為了方便直接返回了全部的屬性數(shù)組,不影響布局但可能會影響性能(如果你的item一屏幕顯示不完,那么這個方法會調用多次,當所有的item都加載完畢后,在滑動collectionView時不會調用該方法的)。
- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath;
該方法不是必須實現(xiàn)的,即便你實現(xiàn)了,我們對collectionView的任何操作,也不會導致系統(tǒng)主動調用該方法。該方法通常用來定制某個IndexPath的item的屬性。當然我們也可以重寫這個方法,將布局時相關的屬性設置放在這里,在- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect 或者 - (void)prepareLayout 中 需要創(chuàng)建用來返回給系統(tǒng)的屬性數(shù)組 主動調用這個方法,并添加帶可變數(shù)組中去返回給系統(tǒng)。當然我們也可以在 - (void)prepareLayout 中 通過[UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:[NSIndexPath indexPathForRow:i inSection:0]] 獲取 每個indexPath的attributes,在- (void)prepareLayout中設置所有item的屬性。看需求以及個人喜歡。
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds;
用來刷新layout的,當我們返回yes的時候。如果我們的需求不需要實時的刷新layout,那么最好判斷newBounds 和 我們的collectionView的bounds是否相同,不同時返回yes;(例如蘋果官方的lineLayout,因為每次滑動都要放大item,所以這了就直接返回yes)。
以蘋果官方的lineLayout為例,這個是對UICollectionViewFlowLayout的擴充,