實現(xiàn)瀑布流簡單窜醉,實現(xiàn)分區(qū)瀑布流宪萄,并且每個區(qū)的瀑布流的列數(shù)不一樣且有區(qū)頭和區(qū)尾,就不是太容易了榨惰。我嫌麻煩不愿意自己寫(——>我承認懶拜英,不愿意動腦子 *V*)開始在網(wǎng)上找了好多,都是僅僅一個區(qū)的瀑布流琅催,沒區(qū)頭和區(qū)尾居凶,完全滿足不了我的需求。沒辦法藤抡,產品的需求在那侠碧,不能不做吧,于是自己靜下心來開始寫缠黍。
其代理方法和屬性模仿UICollectionViewFlowLayout 所寫弄兜,使用方法和UICollectionViewFlowLayout類似
功能描述:
1 > 滿足UICollectionViewFlowLayout提供的普通的線性布局和網(wǎng)格布局
2>? 滿足單區(qū)和多區(qū)的瀑布流布局。
3> 滿足多區(qū)瀑布流時每個區(qū)的列數(shù)可以不同
4> 滿足設置header和footer
5> 滿足設置header和footer的間距
注意:本文不涉及到裝飾視圖的相關代理方法以及計算瓷式。
首先要明白的事情:collectionView與collocationViewLayout的關系替饿。
collocationView負責展示,collectionviewLayout負責提供如何展示蒿往,包括cell的大小位置盛垦,header和footer的大小位置等湿弦,UICollectionViewFlowLayout 繼承自UICollectionViewLayout是蘋果公司封裝好的layout瓤漏,可以實現(xiàn)簡單的網(wǎng)格和線性布局,當cell的大小和間距一樣時可以用UICollectionViewFlowLayout,如果要實現(xiàn)比較復雜的布局蔬充,就需要自定義了蝶俱。
其次,要了解UICollectionViewLayoutAttributes 類的屬性饥漫,以下是每一個cell的屬性榨呆,都是通過UICollectionViewLayoutAttributes屬性體現(xiàn)出來的。
CGRect frame; // cell的大小已經x庸队,y值
CGPoint center;//cell的中心點
CGSize size;// cell的size
CATransform3D transform3D;// cell的3D旋轉
CGRect bounds NS_AVAILABLE_IOS(7_0);
CGAffineTransform transform NS_AVAILABLE_IOS(7_0); // cell 的旋轉
CGFloat alpha;//alp值
NSInteger zIndex; // default is 0 //z軸
getter=isHidden) BOOL hidden; // As an optimization,
還有积蜻,要理解UICollectionViewLayout的幾個方法:
1, prepareLayout :是專門用來準備布局的彻消,在prepareLayout方法里面我們可以事先就計算后面要用到的布局信息并存儲起來竿拆,防止后面方法多次計算,提高性能宾尚。例如丙笋,我們可以在此方法就計算好每個cell的屬性、整個CollectionView的內容尺寸等等煌贴。此方法在布局之前會調用一次御板,之后只有在調用invalidateLayout、shouldInvalidateLayoutForBoundsChange:返回YES和UICollectionView刷新的時候才會調用牛郑。
2怠肋,- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath 返回對應的indexPath的cell的attributes
3- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath? 返回對應的header和footer的attributes
4 - (CGSize)collectionViewContentSize ;collectionView的size 這個size不是可視范圍的size是整個collectionView的size
5 - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect? 返回在rect范圍內所有cell footer和head的attribute
了解以上的幾點就可以開始計算了淹朋。計算的順序是從上到下灶似,即從區(qū)頭到每個區(qū)的cell再到區(qū)尾
設置一些數(shù)組用于存儲計算好的值:如下
//存放attribute的數(shù)組
@property (nonatomic, strong) NSMutableArray *attrsArray;
//存放當前區(qū)中各個列的當前的高度
@property (nonatomic, strong) NSMutableArray *columnHeights;
//collectionView的Content的高度
@property (nonatomic, assign) CGFloat contentHeight;
//記錄每個區(qū)最高的
@property (nonatomic, assign) CGFloat lastContentHeight;
//每個區(qū)的區(qū)頭和上個區(qū)的區(qū)尾的距離
@property (nonatomic, assign) CGFloat spacingWithLastSection;
首先是重寫 prepareLayout方法,也是最重要的一步瑞你。在此方法中完成初始化酪惭。所有的計算都置為零。
第一步:通過 [self.collectionView numberOfSections] 方法獲取collectionView中一共有幾個區(qū)者甲。設置一個for循環(huán)春感。
第二步:通過 - (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath 獲取每個header的屬性。計算完成之后把attributes添加到attrsArray 數(shù)組中 虏缸,同時還有根據(jù)sectionInsets 等參數(shù)改變contentHeight 的高度
第三步: 設置區(qū)頭完成之后鲫懒,在循環(huán)中根據(jù) [self.collectionView numberOfItemsInSection:i] 獲取相應的區(qū)有多少個cell
在這一步中計算是最麻煩的」粽蓿可以分為如下步驟:
1> 計算每一個cell的frame窥岩。 根據(jù)此區(qū)中一共有幾列和屏幕的寬度,以及每個cell的之間的間距宰缤,計算出每個cell的寬度颂翼,因為高度是外面?zhèn)鬟^來的晃洒,所以高度不需要計算 。那么還需要知道cell的x值和y值朦乏。
x值:首先取出當前區(qū)的中哪一列最低球及。
NSInteger tempMinColumn = 0; //默認第 0 列最小
CGFloat minColumnHeight = [self.columnHeights[0] doubleValue]; // 取出最小的那一列的高度
for (NSInteger i = 0; i < self.columnCount; i ++) {
CGFloat columnH = [self.columnHeights[i] doubleValue];
if (minColumnHeight > columnH) {
minColumnHeight = columnH;
tempMinColumn = i;
} else {}
}
tempMinColumn 就是最小的那一列
x值就可以根據(jù)sectionInsets , 每個cell的左右間距呻疹,和cell的寬度算出 CGFloat cellX = self.sectionInsets.left + tempMinColumn * (cellWeight + self.interitemSpacing);
y值:上面已經求出高度最小的那一列吃引,以及最小的那一列的高度。
y值就 cellY = minColumnHeight
注意://如果cell的y值不等于上個區(qū)的最高的高度 即不是此區(qū)的第一列 要加上此區(qū)的每個cell的上下間距
if (cellY != self.lastContentHeight) {
cellY += self.lineSpacing;
} else {}
這樣就可以知道了 cell的frame了刽锤, 即attributes.frame = CGRectMake(cellX, cellY, cellWeight, cellHeight);
2>? 要更新 contentHeight (當前collectionView的內容的高度) 和columnHeights(當區(qū)的每列的高度或者說每列的最后一個cell的y值 + height)
那么這樣相應cell的值就計算完畢 镊尺,在此函數(shù)返回值處添加到attrsArray 中去。
第四部:同header的計算方式一樣 在- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath 計算footer的frame
一共多少個區(qū) 并思,每個區(qū)的header的frame是多少鹅心,每個區(qū)中有多少個cell 每個cell的frame是多少 ,每個區(qū)的footer的frame是多少纺荧,以此循環(huán)計算出所有的attributes旭愧,在- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect 返回計算的attributes
注意 :在計算每個attributes時 collectionView的內容的高度即contentHeight collectionView上個區(qū)的最高的那一列的高度即lastContentHeight 都在改變。
在- (CGSize)collectionViewContentSize {
return CGSizeMake(self.collectionView.frame.size.width, self.contentHeight);
} 中返回collectionView ContentSize 完成布局宙暇。
為了支持擴展性和易用性输枯,我完全模仿 UICollectionViewFlowLayout 的用法設置代理方法和屬性。至于其使用方法占贫,和UICollectionViewFlowLayout 一樣的桃熄。代理方法和屬性如下。
@property (nonatomic, weak) id delegate;
// 區(qū)的sectionInsets
@property (nonatomic,assign) UIEdgeInsets sectionInsets;
//每個區(qū)的列數(shù)
@property (nonatomic,assign) NSInteger columnCount;
// 每個cell的上下間距
@property (nonatomic,assign) CGFloat lineSpacing;
//每個cell的左右間距
@property (nonatomic,assign) CGFloat interitemSpacing;
//header的size
@property (nonatomic,assign) CGSize headerReferenceSize;
// footer的size
@property (nonatomic,assign) CGSize footerReferenceSize;
上述的這些參數(shù) 如果每個區(qū)都一樣型奥,則可以在layout初始化的時候設置瞳收,如過每個區(qū)的參數(shù)設置都不一樣,比如第一個區(qū)是兩列厢汹,第二個區(qū)是一列螟深,不用擔心,用代理烫葬。
代理方法支持分區(qū)設置這些參數(shù)界弧。
@protocol JWCCustomLayoutDelegate
@required
// cell 高
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(JWCCustomLayout *)collectionViewLayout heightForRowAtIndexPath:(NSIndexPath *)indexPath itemWidth:(CGFloat)itemWidth ;
@optional
// headersize
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(JWCCustomLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section;
// footer 的 size
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(JWCCustomLayout *)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section;
// 每個區(qū)的邊距
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(JWCCustomLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section;
// 每個區(qū)多少列
- (NSInteger)collectionView:(UICollectionView *)collectionView layout:(JWCCustomLayout *)collectionViewLayout columnNumberAtSection:(NSInteger )section;
// 每個區(qū)多少中行距
- (NSInteger)collectionView:(UICollectionView *)collectionView layout:(JWCCustomLayout *)collectionViewLayout lineSpacingForSectionAtIndex:(NSInteger)section;
// 每個 item 之間的左右間距
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(JWCCustomLayout*)collectionViewLayout interitemSpacingForSectionAtIndex:(NSInteger)section;
// 本區(qū)區(qū)頭和上個區(qū)區(qū)尾的間距
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(JWCCustomLayout*)collectionViewLayout spacingWithLastSectionForSectionAtIndex:(NSInteger)section;? (注意:在collectionViewFolwLayout中是無法設置當前的區(qū)頭和上個區(qū)尾的間距的,為了彌補這一缺憾搭综,特此添加這個方法)
以上只是大致計算步驟垢箕,具體實現(xiàn)代碼見demo
轉載請注明出處? 掘金老 JI? https://juejin.im/post/5a5274e46fb9a01c9f5b3eee 謝謝
看完如果對你有用 請點贊鼓勵下中不中???? ?? ??