自定義collocationViewLayout實現(xiàn)瀑布流

實現(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 謝謝


看完如果對你有用 請點贊鼓勵下中不中???? ?? ??

區(qū)頭和區(qū)尾設置間距 兑巾,第0區(qū)三列第一區(qū)四列 效果圖



單個區(qū)兩列效果圖
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末条获,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蒋歌,更是在濱河造成了極大的恐慌帅掘,老刑警劉巖委煤,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異锄开,居然都是意外死亡素标,警方通過查閱死者的電腦和手機称诗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門萍悴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人寓免,你說我怎么就攤上這事癣诱。” “怎么了袜香?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵撕予,是天一觀的道長。 經常有香客問我蜈首,道長实抡,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任欢策,我火速辦了婚禮吆寨,結果婚禮上,老公的妹妹穿的比我還像新娘踩寇。我一直安慰自己啄清,他們只是感情好,可當我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布俺孙。 她就那樣靜靜地躺著辣卒,像睡著了一般。 火紅的嫁衣襯著肌膚如雪睛榄。 梳的紋絲不亂的頭發(fā)上荣茫,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天,我揣著相機與錄音场靴,去河邊找鬼计露。 笑死,一個胖子當著我的面吹牛憎乙,可吹牛的內容都是我干的票罐。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼泞边,長吁一口氣:“原來是場噩夢啊……” “哼该押!你這毒婦竟也來了?” 一聲冷哼從身側響起阵谚,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤蚕礼,失蹤者是張志新(化名)和其女友劉穎烟具,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體奠蹬,經...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡朝聋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了囤躁。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片冀痕。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖狸演,靈堂內的尸體忽然破棺而出言蛇,到底是詐尸還是另有隱情,我是刑警寧澤宵距,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布腊尚,位于F島的核電站,受9級特大地震影響满哪,放射性物質發(fā)生泄漏婿斥。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一哨鸭、第九天 我趴在偏房一處隱蔽的房頂上張望民宿。 院中可真熱鬧,春花似錦兔跌、人聲如沸勘高。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽华望。三九已至,卻和暖如春仅乓,著一層夾襖步出監(jiān)牢的瞬間赖舟,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工夸楣, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留宾抓,地道東北人。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓豫喧,卻偏偏與公主長得像石洗,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子紧显,可洞房花燭夜當晚...
    茶點故事閱讀 44,592評論 2 353