UICollectionView詳解

本篇文章主要是書《UICOllectionView The Complete Guide》的讀書筆記,對(duì)比iCrousel源碼,并用UICollectionView來(lái)實(shí)現(xiàn)iCrousel提供的部分的卡片效果众旗。前段時(shí)間做了一個(gè)左右滑動(dòng)界面的需求又厉,用的是三個(gè)UICollectionView相互嵌套來(lái)完成了,在做的過(guò)程中同事說(shuō)可以使用iCrousel來(lái)實(shí)現(xiàn),但是對(duì)iCrousel不太熟悉败晴,最終我還是使用的是UICollectionView,先完成任務(wù)之后開始研究iCrousel栽渴。結(jié)合著這個(gè)過(guò)程中遇到的問(wèn)題尖坤,自己把iCrousel的源碼看了一遍,為了看的懂源碼闲擦,中間有看了一本《Core Animation Advanced Techniques》慢味。因?yàn)檫@本書已經(jīng)有大神翻譯好了,有時(shí)候原版看著費(fèi)勁的時(shí)候就對(duì)著翻譯看墅冷,但是在看《UICollectionView The Complete Guide》的時(shí)候就沒(méi)有這么幸運(yùn)了纯路,在網(wǎng)上一直沒(méi)有找到譯本,只能看原版寞忿。還記得需求是8月初的時(shí)候做的驰唬,當(dāng)我學(xué)完相關(guān)知識(shí)的時(shí)候已經(jīng)到了十一月底了,當(dāng)然中間還有些公司的任務(wù)要開發(fā)腔彰,中途還看了一些其他的書籍叫编,想著如果文筆好的話還能寫個(gè)雞湯類的讀書筆記啥的,但是寫了點(diǎn)東西才知道霹抛,自己能把一個(gè)技術(shù)點(diǎn)寫清楚已經(jīng)很費(fèi)勁了搓逾,還是要繼續(xù)學(xué)習(xí)啊~
趁著剛剛看完,做一個(gè)讀書筆記杯拐,之后就不用再去翻書找知識(shí)點(diǎn)了霞篡。

UICollectionView The Complete Guide

概述

看了下UICollectionView,覺(jué)的這個(gè)是一個(gè)有點(diǎn)像RN的組件端逼,內(nèi)容和布局完全分離的設(shè)計(jì)朗兵,UICollectionView負(fù)責(zé)界面部分,UICollectionViewlayout負(fù)責(zé)UIcollectionView的布局裳食,具體的每個(gè)元素的布局就交給UICollectionViewLayoutAttributes,另外attributes也是可以進(jìn)行擴(kuò)展的矛市,比如需要加入maskView或者改變layer的屬性芙沥,都可以在attributes里面進(jìn)行自己的定義诲祸。

iCrousel的主要的實(shí)現(xiàn)方式是將view加載到視圖的中間,然后根據(jù)設(shè)定好的幾種展示風(fēng)格設(shè)計(jì)好transform3D而昨。比較意外的是沒(méi)有使用UIScrollview來(lái)實(shí)現(xiàn)視圖的滾動(dòng)救氯,而是使用逐幀動(dòng)畫的原理,根據(jù)ios設(shè)備屏幕的刷新速度來(lái)計(jì)算每一幀的所有view的位置歌憨。ios設(shè)備的刷新頻率是60hz着憨,也就是說(shuō)一秒鐘60次,結(jié)合動(dòng)畫一秒24幀就不會(huì)感覺(jué)卡頓务嫡,難怪動(dòng)畫會(huì)這么流暢甲抖。

因?yàn)閁ICollectionView是UIScrollView的子類漆改,而iCrousel是計(jì)算每個(gè)item的偏移,所以實(shí)現(xiàn)方式上也是有很大的差異准谚,iCrousel需要手動(dòng)計(jì)算挫剑,而UICollectionView可以直接使用UIScrollview帶來(lái)的便利。

重用問(wèn)題

在UICollectionView中重用的控件有三種柱衔,分別是UICollectionViewCell樊破、SupplementatyView和DecorationView,其中UICollectionViewCell就不用多說(shuō)了唆铐,SupplementaryView指的是header和footer哲戚。DecorationView指的是裝飾圖,既然是裝飾圖艾岂,那么應(yīng)該是獨(dú)立于view的顺少,所以是在layout里面進(jìn)行設(shè)置的。這兩個(gè)view是繼承UICollectionReusableView的王浴,所以UICollectionView幫我們都做好了重用祈纯。

從iCrousel中可以大概猜測(cè)到重用的機(jī)制是怎么實(shí)現(xiàn)的。在iCrousel里面維護(hù)了兩個(gè)隊(duì)列叼耙,一個(gè)是屏幕上可見items的隊(duì)列腕窥,另一個(gè)是不可見的items的隊(duì)列,也就是重用隊(duì)列筛婉。實(shí)時(shí)的更新兩個(gè)隊(duì)列簇爆,每次先檢查重用隊(duì)列里面有沒(méi)有可以重復(fù)使用的item,如果有的話就任取一個(gè)拿來(lái)使用爽撒,如果沒(méi)有話的再新建一個(gè)入蛆。

類比到UICollectionView里面的話,自我感覺(jué)應(yīng)該是UICollectionReusableView或者UICollectionViewCell被加入到重用隊(duì)列的時(shí)候會(huì)觸發(fā)一個(gè)prepareForReuse的鉤子方法硕勿,在這個(gè)方法里面我們就可以做一些view被重用的準(zhǔn)備哨毁。

UICollectionView

UICollectionView的用法與UITableView的用法類似,如果是創(chuàng)建一個(gè)簡(jiǎn)單的UICollectionView界面的話源武,那么完全可以像使用UITableView一樣來(lái)使用扼褪。其方法也是實(shí)現(xiàn)類似的dataSource和Delegate。但距離UITableView框架問(wèn)世已經(jīng)過(guò)去了好多年了粱栖,隨著每一代ios系統(tǒng)的升級(jí)话浇,UITableView也帶來(lái)了很多的變化,畢竟有一些局限性闹究。所有就有了UICollectionView幔崖。

UICollectionViewCell

首先看一下UICollectionViewCell的層次結(jié)構(gòu):


UICollectionCell層次

從這張圖上我們可以看出來(lái),UICollectionViewCell之上還有還有三個(gè)View,分別是backgroundView和selectedBackgroundView赏寇,最外層的才是contentView吉嫩,從字面上理解就是背景圖層,選中的背景圖層嗅定,最后才是我們編輯的內(nèi)容圖層率挣。所以我們自定義的view應(yīng)該是加上contentView上面才對(duì)。另外我們使用xib文件或者是storyboard文件創(chuàng)建的CollectionViewCell的時(shí)候不會(huì)看到有其他的圖層露戒,甚至看不到像tableview一樣的contentView椒功,是因?yàn)槲覀儎?chuàng)建的view就是默認(rèn)添加到contentView上面的。所以用代碼來(lái)構(gòu)建頁(yè)面的時(shí)候要注意添加到contentView上面來(lái)智什,這樣才不會(huì)破壞UICollectionViewCell的層級(jí)結(jié)構(gòu)动漾,當(dāng)我們使用到選中態(tài)的時(shí)候才不會(huì)發(fā)生不必要的麻煩(現(xiàn)在終于知道了,其實(shí)自己bug多的原因真的是對(duì)知識(shí)的一知半解導(dǎo)致的)荠锭。另外selectedBackgroundView和backgroundView都是option的旱眯,當(dāng)有的時(shí)候才會(huì)加入到view的層級(jí)當(dāng)中。

性能優(yōu)化

在之前core_animation筆記里面有提到tableView加載很多圖片時(shí)的優(yōu)化問(wèn)題证九。后臺(tái)加載圖片删豺,后臺(tái)解壓圖片(png格式比jpeg塊),避免頻繁的離屏渲染等方面來(lái)加載圖片愧怜。另外這本書的前半部分還有使用Instruments來(lái)分析哪個(gè)方法造成了界面的卡頓呀页,界面的卡頓也就說(shuō)掉幀的問(wèn)題,因?yàn)楹臅r(shí)任務(wù)造成沒(méi)有達(dá)到60Hz的渲染拥坛,就會(huì)有卡頓的現(xiàn)象出現(xiàn)蓬蝶。通過(guò)Instruments的Core Animation工具就能分析出哪個(gè)方法耗時(shí)較長(zhǎng),從而定位到問(wèn)題猜惋。

離屏渲染是將渲染好的紋理緩存在GPU丸氛,不需要每次重新渲染,對(duì)高頻率使用的圖層優(yōu)化較大著摔,比如把UICollectionViewCell的shouldRasterize設(shè)置成YES來(lái)觸發(fā)離屏渲染缓窜,這樣在做動(dòng)畫的的時(shí)候不用每一幀都重復(fù)渲染,減少GPU的壓力谍咆。直接將圖層合成到幀的緩沖區(qū)中(在屏幕上)比先創(chuàng)建屏幕外緩沖區(qū)禾锤,然后渲染到紋理中,最后將結(jié)果渲染到幀的緩沖區(qū)中要廉價(jià)很多卧波。因?yàn)檫@其中涉及兩次昂貴的環(huán)境轉(zhuǎn)換(轉(zhuǎn)換環(huán)境到屏幕外緩沖區(qū)时肿,然后轉(zhuǎn)換環(huán)境到幀緩沖區(qū))。

UICollectionViewLayout

UICollectionViewLayout是一個(gè)沒(méi)有實(shí)現(xiàn)具體方法的類(是否可以叫做抽象類港粱,因?yàn)榇_實(shí)很多方法需要重載才有有效),只有繼承并實(shí)現(xiàn)相關(guān)的方法之后才能夠使用。蘋果的SDK已經(jīng)幫我們實(shí)現(xiàn)了一個(gè)流式布局的類查坪,就是UICollectionViewFlowLayout寸宏,一般的流式布局都是可以通過(guò)繼承這個(gè)類來(lái)實(shí)現(xiàn)。我們可以在flowLayout里面設(shè)置itemSize偿曙,sectionInset氮凝,item間距,item行距等基本的Cell的設(shè)置望忆。設(shè)置好cell的基本屬性之后罩阵,剩下的flowlayout就會(huì)幫我們把布局根據(jù)流布局的規(guī)則計(jì)算出來(lái)了。一般我們使用flowLayout的之類已經(jīng)足夠了启摄。layout管理著UICollectionView的布局稿壁,也就是說(shuō)它管理著界面上能看到的一切,無(wú)非就是UICollectionViewCell歉备,SupplementatyView和DecorationView傅是。每個(gè)元素對(duì)應(yīng)了一個(gè)UICollectionViewLayoutAttributes,通過(guò)這個(gè)管理attributes屬性就能夠改變UICollectionView的布局蕾羊,主要是要實(shí)現(xiàn)以下幾個(gè)方法:

 - (NSArray *)layoutAttributesForElements:(Rect)rect;

這個(gè)方法會(huì)返回在這個(gè)rect里面所有的attributes數(shù)組喧笔,可以通過(guò)復(fù)寫這個(gè)方法來(lái)編輯SupplementatyView和DecorationView的attributes屬性,判斷attributes是否為cell的方法就是判斷attributes的representedElementKind屬性,當(dāng)前為nil的時(shí)候就是cell龟再。具體區(qū)分的話就是要使用representedElementCategory屬性了书闸。

這個(gè)方法之后還有針對(duì)每個(gè)indexPath的修改attributes的方法,也是屬于同一種方法類型利凑,具體可以查閱文檔(個(gè)人感覺(jué)文檔已經(jīng)很清楚了梗劫,不過(guò)很多知識(shí)還是需要看一些例子才能將這些零碎的知識(shí)點(diǎn)整合起來(lái))。

- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds;

這個(gè)方法是用來(lái)判斷是否CollectionView的bounds發(fā)生變化的時(shí)候就更新attributes截碴,所以當(dāng)我們需要實(shí)時(shí)的更新attributes的時(shí)候梳侨,這個(gè)方法就要返回YES。因?yàn)閁ICollectionView是UIScrollview的子類類日丹,而UIScrollview的實(shí)現(xiàn)方式就是UIView改變自身的bounds從而改變可見的范圍走哺,所以這個(gè)方法就是當(dāng)scrollview發(fā)生偏移的時(shí)候(bounds發(fā)生變化)就將layout無(wú)效,重新計(jì)算layout哲虾。這里還需要注意一個(gè)問(wèn)題丙躏,就是屏幕發(fā)生旋轉(zhuǎn)的時(shí)候bounds也會(huì)發(fā)生改變,并且在旋轉(zhuǎn)的時(shí)候默認(rèn)使用的動(dòng)畫是移除所有items和添加所有items所用動(dòng)畫束凑,所以如果自定義了item出現(xiàn)和消失動(dòng)畫的話就會(huì)在旋轉(zhuǎn)屏幕的時(shí)候?qū)γ恳粋€(gè)item重復(fù)做動(dòng)畫晒旅。解決方案在網(wǎng)上有查到一個(gè)方法,詳見:UICollectionView動(dòng)畫

initialLayoutAttributesForAppearingItemAtIndexPath:
initialLayoutAttributesForAppearingSupplementaryElementOfKind:atIndexPath:
initialLayoutAttributesForAppearingDecorationElementOfKind:atIndexPath:
finalLayoutAttributesForDisappearingItemAtIndexPath:
finalLayoutAttributesForDisappearingSupplementaryElementOfKind:atIndexPath:
finalLayoutAttributesForDisappearingDecorationElementOfKind:atIndexPath:

這些方法就是上面所說(shuō)的定義item消失和添加時(shí)候的動(dòng)畫汪诉,當(dāng)然也可以對(duì)Supplementary view和Decoration view的動(dòng)畫废恋。

還有兩個(gè)方法也很重要谈秫,用來(lái)識(shí)別bounds改變的動(dòng)畫和update的動(dòng)畫,同時(shí)用這兩個(gè)方法可以避免上面所說(shuō)的屏幕旋轉(zhuǎn)動(dòng)畫的異常鱼鼓。

- prepareForCollectionViewUpdates:
- prepareForAnimatedBoundsChange:

第一個(gè)方法是在view更新的時(shí)候觸發(fā)的方法拟烫,第二個(gè)方法是在bounds發(fā)生改變的時(shí)候觸發(fā)的方法,在這兩個(gè)方法里面可以分別申請(qǐng)兩個(gè)數(shù)組來(lái)區(qū)分兩種動(dòng)畫迄本。

UICollectionViewLayoutAttributess

這個(gè)名字比較長(zhǎng)的類似用來(lái)存儲(chǔ)UICollectionView元素布局的屬性硕淑,可以改變frame,bounds嘉赎,center置媳,size,transform公条,transform3D拇囊,alpha,zIndex赃份,hidden等屬性寂拆,其中zIndex反映的是view的層級(jí)關(guān)系,默認(rèn)的zIndex值是0抓韩,大的在層級(jí)的上面纠永,小的在下面。transform3D可以給每個(gè)元素添加transform3D屬性谒拴,這樣的話就可以仿照iCrousel來(lái)實(shí)現(xiàn)相似的效果了尝江。

自定義UICollectionViewLayoutAttributess屬性

對(duì)于繼承于UICollectionViewLayoutAttributess的子類,我們可以自定義一些items需要表現(xiàn)的屬性英上,比如是否光柵化炭序,自定義maskView的透明度之類的我們自定義items或者Supplementary和Decoration的表現(xiàn)。比如說(shuō)我要根據(jù)偏移來(lái)計(jì)算不同的maskView 透明度的變化苍日,那么就要給UICollectionViewLayoutAttributess子類加上屬性alpha惭聂,同時(shí)要復(fù)寫copy和equal方法。對(duì)于自定義的屬性相恃,我們?cè)趯?shí)現(xiàn)itemCell的時(shí)候需要復(fù)寫方法 -applyLayoutAttributes: 辜纲,在這個(gè)方法里面可以接受作用于這個(gè)itemCell的attributes,對(duì)于我們自定義的屬性拦耐,需要在這個(gè)方法里面讓itemCell根據(jù)屬性做一些相應(yīng)的改變耕腾。

關(guān)于光柵化會(huì)觸發(fā)離屏渲染,上面也有所離屏渲染會(huì)帶來(lái)很多開銷杀糯,但是對(duì)于cell圖層比較多扫俺,合成起來(lái)比較費(fèi)時(shí),并且頻繁重用的view來(lái)說(shuō)固翰,進(jìn)行離屏渲染是很有幫助的狼纬。

小結(jié)

關(guān)于UICollectionView的知識(shí)點(diǎn)大約就是這么多羹呵,但是具體要實(shí)現(xiàn)哪些動(dòng)畫還是需要我們自己來(lái)實(shí)現(xiàn)相應(yīng)的算法。相比于iCrousel畸颅,UICollectionView已經(jīng)實(shí)現(xiàn)好了重用機(jī)制担巩,并且將layout的代碼獨(dú)立出來(lái)方援,也是使用transform3D屬性來(lái)改變item的位置没炒,所以用UICollectionView實(shí)現(xiàn)iCrousel的布局方式只需要將其對(duì)每個(gè)item的transform3D算法轉(zhuǎn)移到item對(duì)應(yīng)的attributes里面就可以了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末犯戏,一起剝皮案震驚了整個(gè)濱河市送火,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌先匪,老刑警劉巖种吸,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異呀非,居然都是意外死亡坚俗,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門岸裙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)猖败,“玉大人,你說(shuō)我怎么就攤上這事降允《魑牛” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵剧董,是天一觀的道長(zhǎng)幢尚。 經(jīng)常有香客問(wèn)我,道長(zhǎng)翅楼,這世上最難降的妖魔是什么尉剩? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮毅臊,結(jié)果婚禮上理茎,老公的妹妹穿的比我還像新娘。我一直安慰自己褂微,他們只是感情好功蜓,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著宠蚂,像睡著了一般式撼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上求厕,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天著隆,我揣著相機(jī)與錄音扰楼,去河邊找鬼。 笑死美浦,一個(gè)胖子當(dāng)著我的面吹牛弦赖,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播浦辨,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼蹬竖,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了流酬?” 一聲冷哼從身側(cè)響起币厕,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎芽腾,沒(méi)想到半個(gè)月后旦装,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡摊滔,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年阴绢,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片艰躺。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡呻袭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出描滔,到底是詐尸還是另有隱情棒妨,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布含长,位于F島的核電站券腔,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏拘泞。R本人自食惡果不足惜纷纫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望陪腌。 院中可真熱鬧辱魁,春花似錦、人聲如沸诗鸭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)强岸。三九已至锻弓,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蝌箍,已是汗流浹背青灼。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工暴心, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人杂拨。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像弹沽,于是被迫代替她去往敵國(guó)和親檀夹。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

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