詳細(xì)分享UICollectionView的自定義布局(瀑布流, 線性, 圓形...)

前言

本篇文章不是分享collectionView的詳細(xì)使用教程, 而是屬于比較'高級(jí)'的collectionView使用技巧, 閱讀之前, 我想你已經(jīng)很熟悉collectionView的基本使用, 如果不是很熟悉, 建議在以后熟悉一下。那么在本篇結(jié)束后, 你也能夠很輕松的使用collectionView來實(shí)現(xiàn), 當(dāng)下比較流行和比較炫酷的效果以及你想要自己實(shí)現(xiàn)的其他的效果。這里就實(shí)現(xiàn)三種比較常用的效果: 線性布局, 瀑布流布局, 圓形布局, 其他的各種自定義的布局你將是會(huì)有能力自己實(shí)現(xiàn)的。

最終效果

一、首先了解下UICollectionViewLayoutAttributes

當(dāng)你看這些屬性的時(shí)候, 有沒有感覺到是一個(gè)view應(yīng)該有的屬性, 實(shí)際上, collectionVIew里面的所有的cell我們并沒有給它直接設(shè)置過他在collectionView上面的frame等屬性, 它的相關(guān)的設(shè)置都是由UICollectionViewLayoutAttributes來完成的。

每一個(gè)cell都對(duì)應(yīng)的有一個(gè)UICollectionViewLayoutAttributes來設(shè)置他的一些屬性, 當(dāng)我們?cè)谛薷乃麑?duì)應(yīng)的UICollectionViewLayoutAttributes的相關(guān)的屬性的時(shí)候, 就間接的實(shí)現(xiàn)了對(duì)響應(yīng)的cell的相關(guān)屬性的修改。

所以我們對(duì)collectionViewCell的很多自定義就落在了對(duì)相應(yīng)的UICollectionViewLayoutAttributes上面

publicvarframe: CGRect

publicvarcenter:?CGPoint

publicvarsize:?CGSize

//?用于實(shí)現(xiàn)一些3D效果

publicvartransform3D:?CATransform3D

@available(iOS?7.0,?*)

publicvarbounds:?CGRect

@available(iOS?7.0,?*)

//?更改transform可以方便的實(shí)現(xiàn)一些縮放,?旋轉(zhuǎn)效果

publicvartransform:?CGAffineTransform

publicvaralpha:?CGFloat

publicvarzIndex:?Int//?default?is?0

//?初始化方法,?分別對(duì)應(yīng)為collectionView里面的幾種reusebleView

//cell

public?convenience?init(forCellWithIndexPath?indexPath:?NSIndexPath)

//SupplementaryView

public?convenience?init(forSupplementaryViewOfKind?elementKind:?String,?withIndexPath?indexPath:?NSIndexPath)

//?DecorationView

public?convenience?init(forDecorationViewOfKind?decorationViewKind:?String,?withIndexPath?indexPath:?NSIndexPath)

二、了解UICollectionViewFlowLayout

要完成collectionView的布局是需要設(shè)置他的屬性 collectionViewLayout, 當(dāng)使用storyboard的時(shí)候是默認(rèn)為UICollectionViewFlowLayout。

UICollectionViewFlowLayout是系統(tǒng)提供的一種網(wǎng)格布局, 通常情況下你只需要設(shè)置一下下面列舉的一些屬性, 就可以達(dá)到普通的collectionView的使用效果---網(wǎng)格效果, 同時(shí)你可以使用UICollectionViewDelegateFlowLayout 來實(shí)現(xiàn)一些比較簡單的動(dòng)態(tài)更改cell的布局的效果。

// 最小的行距

publicvarminimumLineSpacing:?CGFloat

//?最小的列距

publicvarminimumInteritemSpacing:?CGFloat

//?cell的大小

publicvaritemSize:?CGSize

//?collectionView的滾動(dòng)方向

publicvarscrollDirection:?UICollectionViewScrollDirection//?default?is?UICollectionViewScrollDirectionVertical

//?headersize

publicvarheaderReferenceSize:?CGSize

publicvarfooterReferenceSize:?CGSize

publicvarsectionInset:?UIEdgeInsets

三、強(qiáng)大的UICollectionViewLayout

要完成collectionView的布局是需要設(shè)置他的屬性 collectionViewLayout, 當(dāng)使用storyboard的時(shí)候是默認(rèn)為UICollectionViewFlowLayout, 實(shí)際上UICollectionViewFlowLayout是繼承自UICollectionViewLayout, 由系統(tǒng)實(shí)現(xiàn)的一種collectionView的布局。

所以我們可以繼承UICollectionViewLayout來自定義我們想要的布局。

實(shí)現(xiàn)自定義的布局并不是很復(fù)雜, 官方文檔中已經(jīng)說明了相關(guān)的方法, 這里直接分享給大家。

下面是自定義UICollectionViewLayout時(shí)比較常用到的一些方法:

collectionView每次需要重新布局(初始, layout 被設(shè)置為invalidated ...)的時(shí)候會(huì)首先調(diào)用這個(gè)方法prepareLayout()。所以Apple建議我們可以重寫這個(gè)方法來為自定義布局做一些準(zhǔn)備的操作,在cell比較少的情況下, 我們一般都可以在這個(gè)方法里面計(jì)算好所有的cell布局,并且緩存下來, 在需要的時(shí)候直接取相應(yīng)的值即可, 以提高效率。

1

func?prepareLayout()

然后會(huì)調(diào)用layoutAttributesForElementsInRect(rect: CGRect)方法獲取到rect范圍內(nèi)的cell的所有布局, 這個(gè)rect大家可以打印出來看下, 和collectionView的bounds不一樣, size可能比collectionView大一些, 這樣設(shè)計(jì)也許是為了緩沖。Apple要求這個(gè)方法必須重寫, 并且提供相應(yīng)rect范圍內(nèi)的cell的所有布局的UICollectionViewLayoutAttributes, 如果之前我們已經(jīng)計(jì)算好了,就可以直接返回就可以了, 當(dāng)然你可以比如只返回rect范圍內(nèi)的cell的布局,而不是所有的cell的布局, 不過這樣的話你需要設(shè)置下一個(gè)方法

1

func?layoutAttributesForElementsInRect(rect:?CGRect)?->?[UICollectionViewLayoutAttributes]?

當(dāng)collectionView的bounds變化的時(shí)候會(huì)調(diào)用,shouldInvalidateLayoutForBoundsChange(newBounds: CGRect)這個(gè)方法。如果我們的布局是會(huì)時(shí)刻變化的, 需要在滾動(dòng)的過程中重新布局 , 那么我們需要,設(shè)置這個(gè)方法的返回值為true, 默認(rèn)為false。

* 當(dāng)返回值為true的時(shí)候會(huì)將collectionView的layout設(shè)置為invalidated,將會(huì)使collectionView重新調(diào)用上面的prepareLayout()...方法重新獲得布局

* 同時(shí), 當(dāng)屏幕旋轉(zhuǎn)的時(shí)候collectionView的bounds也會(huì)調(diào)用這個(gè)方法,

如果設(shè)置為false, 那么將不會(huì)達(dá)到屏幕適配的效果,

* 需要注意的是, 當(dāng)collectionView執(zhí)行一些操作(delete insert reload)等的時(shí)候,

不會(huì)調(diào)用這個(gè)方法, 會(huì)直接重新調(diào)用上面的prepareLayout()...方法重新獲得布局

1

public?func?shouldInvalidateLayoutForBoundsChange(newBounds:?CGRect)?->?Bool

需要設(shè)置collectionView 的滾動(dòng)范圍 collectionViewContentSize(),自定義的時(shí)候, 必須重寫這個(gè)方法, 并且返回正確的滾動(dòng)范圍, collectionView才能正常的滾動(dòng)

1

public?func?collectionViewContentSize()?->?CGSize

以下方法, Apple建議我們也重寫, 返回正確的自定義對(duì)象的布局。因?yàn)橛袝r(shí)候當(dāng)collectionView執(zhí)行一些操作(delete insert reload)等系統(tǒng)會(huì)調(diào)用這些方法獲取布局, 如果沒有重寫, 可能發(fā)生意想不到的效果。

自定義cell布局的時(shí)候重寫

1

public?func?layoutAttributesForItemAtIndexPath(indexPath:?NSIndexPath)?->?UICollectionViewLayoutAttributes?

自定義SupplementaryView的時(shí)候重寫

1

public?func?layoutAttributesForSupplementaryViewOfKind(elementKind:?String,?atIndexPath?indexPath:?NSIndexPath)?->?UICollectionViewLayoutAttributes?

自定義DecorationView的時(shí)候重寫

1

public?func?layoutAttributesForDecorationViewOfKind(elementKind:?String,?atIndexPath?indexPath:?NSIndexPath)?->?UICollectionViewLayoutAttributes?

這個(gè)方法是當(dāng)collectionView將停止?jié)L動(dòng)的時(shí)候調(diào)用, 我們可以重寫它來實(shí)現(xiàn), collectionView停在指定的位置(比如照片瀏覽的時(shí)候, 你可以通過這個(gè)實(shí)現(xiàn)居中顯示照片...)

1

public?func?targetContentOffsetForProposedContentOffset(proposedContentOffset:?CGPoint,?withScrollingVelocity?velocity:?CGPoint)?->?CGPoint

同時(shí)里面還有很多的方法我們可以重寫來實(shí)現(xiàn)更多的效果, 但是這里, 就先介紹這么多的方法來實(shí)現(xiàn)自定義collectionView的布局。

下面通過例子介紹下具體的使用

圓形布局的實(shí)現(xiàn)

繼承自UICollectionViewLayout, 重寫prepareLayout(),在這里面我們計(jì)算好所有的cell布局

override func prepareLayout() {

//?一定要調(diào)用super

super.prepareLayout()

//?初始化需要的數(shù)據(jù)

//?總的cell

totalNum?=?collectionView!.numberOfItemsInSection(0)

//?每次計(jì)算前需要清零

layoutAttributes?=?[]

//?圓心

center?=?CGPoint(x:?Double(collectionView!.bounds.width?*?0.5),?y:?Double(collectionView!.bounds.height?*?0.5))

//?圓半徑

radius?=?min(collectionView!.bounds.width,?collectionView!.bounds.height)?/?3.0

varindexPath:?NSIndexPath

forindexin0..

重寫方法設(shè)置每個(gè)cell的布局

//?Apple建議要重寫這個(gè)方法,?因?yàn)槟承┣闆r下(delete?insert...)系統(tǒng)可能需要調(diào)用這個(gè)方法來布局

override?func?layoutAttributesForItemAtIndexPath(indexPath:?NSIndexPath)?->?UICollectionViewLayoutAttributes??{

let?attributes?=?UICollectionViewLayoutAttributes(forCellWithIndexPath:?indexPath)

//?設(shè)置cell的大小

attributes.size?=?CGSize(width:?60.0,?height:?60.0)

//?當(dāng)前cell的角度

//?注意類型轉(zhuǎn)換

let?angle?=?2?*?CGFloat(M_PI)?*?CGFloat(indexPath.row)?/?CGFloat(totalNum)

//?一點(diǎn)點(diǎn)數(shù)學(xué)轉(zhuǎn)換

attributes.center?=?CGPoint(x:?center.x?+?radius*cos(angle),?y:?center.y?+?radius*sin(angle))

returnattributes

}

數(shù)學(xué)計(jì)算過程(寫得不好看##<<>>##)

http://cc.cocimg.com/api/uploads/20160621/1466504858311878.jpg" title="1466504858311878.jpg" alt="1271831-1c7c180626674873.jpg">

重寫方法返回計(jì)算好的布局

override?func?layoutAttributesForElementsInRect(rect:?CGRect)?->?[UICollectionViewLayoutAttributes]?

{

returnlayoutAttributes

}

重寫方法設(shè)置collectionView的滾動(dòng)范圍(這里不滾動(dòng))

override?func?collectionViewContentSize()?->?CGSize?{

returncollectionView!.bounds.size

}

這樣就實(shí)現(xiàn)了自定義的圓形布局, 還是比較簡單!!

關(guān)于瀑布流的布局, 自定義過程和這個(gè)相似, 就不貼代碼了, https://github.com/jasnig/CollectionViewLayout"target="_blank">Demo地址里面有詳細(xì)的代碼注釋, 直接大家看代碼吧, 如果對(duì)你有幫助, 歡迎關(guān)注, 歡迎star。

另外Demo里的布局大家是可以直接拿來使用的,以后你也有能力自己實(shí)現(xiàn)各種炫酷的布局效果了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,491評(píng)論 3 416
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,263評(píng)論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,946評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,708評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,186評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,409評(píng)論 0 288
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,939評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,774評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,976評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,209評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,641評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,872評(píng)論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,650評(píng)論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,958評(píng)論 2 373

推薦閱讀更多精彩內(nèi)容