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

其代理方法和屬性模仿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的大小已經(jīng)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值:上面已經(jīng)求出高度最小的那一列宫患,以及最小的那一列的高度刊懈。

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 高

1

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(JWCCustomLayout *)collectionViewLayout heightForRowAtIndexPath:(NSIndexPath *)indexPath itemWidth:(CGFloat)itemWidth ;

@optional

// headersize

1

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(JWCCustomLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section;

// footer 的 size

1

- (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ū)尾的間距的刨疼,為了彌補這一缺憾泉唁,特此添加這個方法)

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末鹅龄,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子亭畜,更是在濱河造成了極大的恐慌扮休,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拴鸵,死亡現(xiàn)場離奇詭異玷坠,居然都是意外死亡蜗搔,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門八堡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來樟凄,“玉大人,你說我怎么就攤上這事兄渺》炝洌” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵挂谍,是天一觀的道長叔壤。 經(jīng)常有香客問我,道長口叙,這世上最難降的妖魔是什么炼绘? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮妄田,結果婚禮上俺亮,老公的妹妹穿的比我還像新娘。我一直安慰自己疟呐,他們只是感情好铅辞,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著萨醒,像睡著了一般斟珊。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上富纸,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天囤踩,我揣著相機與錄音,去河邊找鬼晓褪。 笑死堵漱,一個胖子當著我的面吹牛,可吹牛的內容都是我干的涣仿。 我是一名探鬼主播勤庐,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼好港!你這毒婦竟也來了愉镰?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤钧汹,失蹤者是張志新(化名)和其女友劉穎丈探,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拔莱,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡碗降,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年隘竭,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片讼渊。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡动看,死狀恐怖,靈堂內的尸體忽然破棺而出爪幻,到底是詐尸還是另有隱情弧圆,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布笔咽,位于F島的核電站搔预,受9級特大地震影響,放射性物質發(fā)生泄漏叶组。R本人自食惡果不足惜拯田,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望甩十。 院中可真熱鬧船庇,春花似錦、人聲如沸侣监。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽橄霉。三九已至窃爷,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間姓蜂,已是汗流浹背按厘。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留钱慢,地道東北人逮京。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像束莫,于是被迫代替她去往敵國和親懒棉。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內容