創(chuàng)建自定義布局
在開始創(chuàng)建自定義布局之前,考慮清楚是否有這個必要。UICollectionViewFlowLayout 類提供了大量已經(jīng)對效率進(jìn)行優(yōu)化了的行為,并且可以通過多種方式進(jìn)行調(diào)整,來實(shí)現(xiàn)許多不同類型的標(biāo)準(zhǔn)布局。唯一需要考慮實(shí)現(xiàn)自定義布局是在以下情況下:
- 你想要的布局看前來不像網(wǎng)格或基于線性中斷布局(布局中
items被放置到一行,直到這一行布滿了,然后繼續(xù)布到下一行,直到所有的items被放置),或者需要不止在一個方向上滾動。 - 你想要頻繁地改變所有單元格的位置,而修改已經(jīng)存在的流式布局比創(chuàng)建自定義布局要做更多的工作。
好消息是,從API的角度來看,實(shí)現(xiàn)自定義布局并不難。最困難的部分是執(zhí)行必要的計(jì)算來確定布局中items的位置。當(dāng)你知道了這些items的位置,給集合視圖提供那些信息是很簡單的。
子類化UICollectionViewLayout
對于自定義布局,你想要子類化UICollectionViewLayout,這為你的設(shè)計(jì)提供了一個新的起點(diǎn)。只有少數(shù)方法為你的布局對象提供了核心的行為,并且在你的實(shí)現(xiàn)中是必須的。其余的方法可以根據(jù)需要來重寫以調(diào)整布局行為。核心方法處理以下關(guān)鍵任務(wù):
- 指定可滾動內(nèi)容區(qū)域的大小。
- 為構(gòu)成布局的單元格和視圖提供屬性對象,以便集合視圖可以定位每個單元格和視圖。
雖讓你可以創(chuàng)建一個僅實(shí)現(xiàn)核心方法的功能性布局對象,但如果你也實(shí)現(xiàn)了幾種可選方法,布局可能會更有吸引力。
布局對象使用它的數(shù)據(jù)源提供的信息來創(chuàng)建集合視圖的布局。你的布局通過調(diào)用collectionView屬性的方法來與數(shù)據(jù)源進(jìn)行通信,該方法可以在所有布局的方法中訪問。記住你的集合視圖在布局過程中知道和不知道的內(nèi)容。由于布局過程正在進(jìn)行,集合視圖無法跟蹤視圖的布局或位置。因此,即使布局對象不會限制你調(diào)用集合視圖的任何方法,也不要依賴于集合視圖來計(jì)算布局所需的數(shù)據(jù)以外的其他內(nèi)容。
理解核心布局過程
集合視圖直接與你的自定義布局對象一起工作來管理整個布局過程。當(dāng)集合視圖確定它需要布局信息時,它會讓你的布局對象來提供。例如,集合視圖會在首次顯示或調(diào)整大小時詢問布局信息。你也可以通過調(diào)用布局對象的invalidateLayout方法告訴集合視圖來顯式地更新它的布局。該方法扔掉已經(jīng)存在的布局信息,并強(qiáng)制布局對象生成新的布局信息。
注意:不要將布局對象的
invalidateLayout方法和集合視圖的reloadData方法混淆。調(diào)用invalidateLayout方法不一定會導(dǎo)致集合視圖拋出其現(xiàn)有的單元格和子視圖。而是,它強(qiáng)制布局對象來重新計(jì)算其當(dāng)移動和添加或刪除items時所需的所有布局屬性。如果數(shù)據(jù)源中的數(shù)據(jù)已更改,則reloadData方法是合適的。無論你如何啟動布局更新,實(shí)際的布局過程是一樣的。
在布局過程中,集合視圖會調(diào)用你的布局對象的特定方法。這些方法是你計(jì)算items位置的機(jī)會,并為集合視圖提供所需的主要信息。其他方法也可能被調(diào)用,但是在布局過程中總是按照以下順序調(diào)用這些方法:
- 使用
prepareLayout方法來執(zhí)行提供布局信息所需的前期計(jì)算。 - 使用
collectionViewContentSize方法來根據(jù)初始計(jì)算返回整個內(nèi)容區(qū)域的總體大小。 - 使用
layoutAttributesForElementsInRect:方法來返回指定矩形中的單元格和視圖的屬性。
圖5-1 說明如何使用上述方法生成布局信息

prepareLayout方法是你執(zhí)行任何計(jì)算來確定在布局中單元格和視圖的位置的機(jī)會。至少,你應(yīng)該在這個方法中計(jì)算足夠的信息,以便返回內(nèi)容區(qū)域的整體大小,在步驟2中以返回給集合視圖。
集合視圖使用內(nèi)容的大小來適當(dāng)?shù)嘏渲盟臐L動視圖。例如,如果計(jì)算的內(nèi)容在縱向和橫向上超過當(dāng)前設(shè)備屏幕的邊界,則滾動視圖將進(jìn)行調(diào)整,以便同時在兩個方向上滾動。不像UICollectionViewFlowLayout, 默認(rèn)不調(diào)整布局的內(nèi)容,只在一個方向上滾動。
基于當(dāng)前滾動位置,然后集合視圖調(diào)用你的layoutAttributesForElementsInRect:方法來詢問在特定矩形內(nèi)的單元格和視圖的屬性,這可能或不可能與可見矩形相同。返回那些信息之后,核心布局過程就有效地完成了。
在布局完成之后,你的單元格和視圖的屬性會保持不變,直到你或集合視圖無效化布局。調(diào)用布局對象的nvalidateLayout方法會導(dǎo)致布局過程重新開始,才從prepareLayout方法的新調(diào)用開始。集合視圖在滾動期間能夠自動地?zé)o效你的布局。如果用戶滾動其內(nèi)容,集合視圖會調(diào)用布局對象的shouldInvalidateLayoutForBoundsChange:方法,如果該方法返回YES,則會使布局無效。
注意:記住調(diào)用
invalidateLayout方法不會立即開始布局更新過程是有用的。該方法僅將布局標(biāo)記為與數(shù)據(jù)不一致并需要更新。在下一個視圖更新周期中,集合視圖會檢查其布局是否不一致,如果是則更新它。事實(shí)上,你可以快速連續(xù)地調(diào)用invalidateLayout方法,而不會每次觸發(fā)立即布局更新。
創(chuàng)建布局屬性
你的布局負(fù)責(zé)的屬性對象是UICollectionViewLayoutAttributes類的實(shí)例。在你的應(yīng)用程序中這些實(shí)例可以被多種不同的方法來創(chuàng)建。當(dāng)你的應(yīng)用程序不處理數(shù)千個items時,在準(zhǔn)備布局時才創(chuàng)建這些實(shí)例是有意義的,因?yàn)椴季中畔⒖梢跃彺婧鸵?,而不是即時計(jì)算。如果計(jì)算所有屬性的成本高于應(yīng)用程序緩存的好處,則在請求時創(chuàng)建屬性一樣容易。
無論如何,創(chuàng)建UICollectionViewLayoutAttributes類的新實(shí)例時,請使用以下類方法之一:
layoutAttributesForCellWithIndexPath:layoutAttributesForSupplementaryViewOfKind:withIndexPath:layoutAttributesForDecorationViewOfKind:withIndexPath:
你必須根據(jù)正在顯示的視圖類型使用正確的類方法,因?yàn)榧弦晥D使用該信息從數(shù)據(jù)源對象請求恰當(dāng)類型的視圖。使用錯誤的方法會導(dǎo)致集合視圖在錯誤的地方創(chuàng)建錯誤的視圖,并且你的布局不會按預(yù)期顯示。
創(chuàng)建每個屬性對象之后,為相應(yīng)視圖設(shè)置相關(guān)屬性。至少,設(shè)置視圖在布局中的大小和位置。在布局視圖重疊的情況下,為zIndex屬性分配一個值,以確保重疊視圖的順序一致。其他屬性讓你控制單元格或視圖的可見性或外觀,并可以根據(jù)需要進(jìn)行更改。如果標(biāo)準(zhǔn)的屬性類不適合你的應(yīng)用程序需要,你可以子類化并且擴(kuò)展它以儲存關(guān)于每個視圖的其他信息。在子類化布局屬性時,為了比較你的自定義屬性,必須實(shí)現(xiàn)isEqual:方法,因?yàn)榧弦晥D對其某些操作會使用此方法。
關(guān)于布局屬性的更多信息,請看UICollectionViewLayoutAttributes Class Reference。
準(zhǔn)備布局
在布局周期開始時,布局對象會在布局過程開始前調(diào)用prepareLayout方法。該方法給你一個機(jī)會來計(jì)算稍后通知你的布局的信息。實(shí)現(xiàn)自定義布局不是必須使用prepareLayout方法,但是如果需要,可以作為進(jìn)行初始計(jì)算的機(jī)會。在該方法調(diào)用之后,你的布局必須具有足夠的信息來計(jì)算集合視圖內(nèi)容的大小,即布局過程的下一步。然而,該信息可以從這個最低要求到創(chuàng)建和存儲布局將使用的所有布局屬性對象。使用prepareLayout方法需要你的應(yīng)用程序的基礎(chǔ)架構(gòu),以及有意義于計(jì)算前面和計(jì)算要求。關(guān)于prepareLayout方法的示例,請看Preparing the Layout.
為給定矩形中的items提供布局屬性
在布局過程的最后一步時,集合視圖調(diào)用你的布局對象的layoutAttributesForElementsInRect:方法。該方法的目的是為與指定矩形相交的每個單元格和每個補(bǔ)充視圖或裝飾視圖提供布局屬性。對于一個大的滾動內(nèi)容區(qū)域,集合視圖可能只是詢問當(dāng)前可見的內(nèi)容區(qū)域部分中的items的屬性。在圖5-2中,你的布局對象需要創(chuàng)建屬性對象為當(dāng)前可見內(nèi)容是單元格6到20以及第二個標(biāo)題視圖。你必須準(zhǔn)備為集合視圖的內(nèi)容區(qū)域的任何部分提供布局屬性。這些屬性可能用于促進(jìn)插入或刪除items的動畫。

因?yàn)?code>layoutAttributesForElementsInRect:方法是在你的布局對象的prepareLayout方法之后調(diào)用, 你應(yīng)該已經(jīng)擁有大部分信息,以返回或創(chuàng)建必需的屬性。你的layoutAttributesForElementsInRect:方法的執(zhí)行遵循以下步驟:
- 迭代由
prepareLayout方法生成的數(shù)據(jù),以訪問緩存的屬性或創(chuàng)建新的屬性。 - 檢查每個
item的frame, 看看它是否與傳遞給layoutAttributesForElementsInRect:方法的矩形相交。 - 對于每個相交的
item,將相應(yīng)的UICollectionViewLayoutAttributes對象添加到數(shù)組。 - 返回布局屬性數(shù)組給集合視圖
根據(jù)你如何管理布局信息,你可以在prepareLayout方法中創(chuàng)建UICollectionViewLayoutAttributes對象,或者在layoutAttributesForElementsInRect方法中執(zhí)行此操作。在形成符合應(yīng)用程序需求的實(shí)現(xiàn)時,請牢記緩存布局信息的好處。為單元格重復(fù)計(jì)算新的布局屬性是一項(xiàng)昂貴的操作,可能會對應(yīng)用程序的性能造成明顯的不利影響。也就是說,當(dāng)你的集合視圖管理的items數(shù)目很大時,在請求時創(chuàng)建布局屬性可能會更有意義(針對性能)。這只是一個問題,弄清楚哪個策略對你的應(yīng)用程序來說是最有意義的。
注意:布局對象還需要能夠根據(jù)個別
items提供布局屬性。集合視圖可能出于一些原因請求常規(guī)布局過程之外的信息,包括創(chuàng)建適當(dāng)?shù)膭赢嫛S嘘P(guān)按需提供布局屬性的詳細(xì)信息,請看Providing Layout Attributes On Demand
對于如何實(shí)現(xiàn)layoutAttributesForElementsInRect:的具體示例,請看Providing Layout Attributes.
按需提供布局屬性
集合視圖定期詢問你的布局對象為正式布局過程之外的各個items提供屬性。例如,集合視圖當(dāng)為一個item配置插入和刪除動畫時詢問這些信息。你的布局對象必須準(zhǔn)備為每個單元格、補(bǔ)充視圖和其支持的裝飾視圖提供布局屬性。你通過重寫下列方法來做這些:
layoutAttributesForItemAtIndexPath:layoutAttributesForSupplementaryViewOfKind:atIndexPath:layoutAttributesForDecorationViewOfKind:atIndexPath:
你的這些方法的實(shí)現(xiàn)應(yīng)該為給定的單元格或視圖獲取當(dāng)前的布局屬性。每個自定義布局對象都被預(yù)期實(shí)現(xiàn)layoutAttributesForItemAtIndexPath:方法。如果你的布局不包含任何補(bǔ)充視圖,你不需要重寫layoutAttributesForSupplementaryViewOfKind:atIndexPath:方法。相同的,如果你的布局不包含裝飾視圖,不需要重寫layoutAttributesForDecorationViewOfKind:atIndexPath:方法。當(dāng)返回屬性時,你不應(yīng)該更新布局屬性。如果你需要改變布局信息,無效化布局對象,并讓它在隨后的布局周期中更新數(shù)據(jù)。
連接自定義布局供使用
有兩種方式來關(guān)聯(lián)自定義布局到集合視圖:以編程方式或通過故事板。集合視圖通過一個可寫的屬性collectionViewLayout來關(guān)聯(lián)它的布局。要將布局設(shè)置為自定義實(shí)現(xiàn),請將集合視圖的布局屬性設(shè)置為自定義布局對象的實(shí)例。清單5-1顯示所需的代碼行。
清單5-1 關(guān)聯(lián)自定義布局
self.collectionView.collectionViewLayout = [[MyCustomLayout alloc] init];
否則,從你的故事板,打開“文檔大綱”面板并選擇你的集合視圖(它列在控制器的下拉菜單中)。選擇集合視圖后,在“實(shí)用程序”窗口打開“屬性”檢查器,并在標(biāo)簽有集合視部分的下方將“布局”選項(xiàng)從“流式”改成“自定義”。它下面的選項(xiàng)從滾動方向更改為類,現(xiàn)在可以選擇自定義布局類。
使你的自定義布局更具吸引力
在布局過程中為每個單元格和視圖提供布局屬性是必需的,但是用你的自定義布局有其他的行為可以提高用戶體驗(yàn)。實(shí)現(xiàn)這些行為是可選的但推薦使用。
通過補(bǔ)充視圖提高內(nèi)容
補(bǔ)充視圖是與集合視圖的單元格分離開來的,并有它自己的布局屬性集合。和單元格一樣,這些視圖被數(shù)據(jù)源對象提供,但是它們的目的是來增強(qiáng)應(yīng)用程序的主要內(nèi)容。例如,UICollectionViewFlowLayout為分區(qū)頭和分區(qū)尾來使用補(bǔ)充視圖。另一個應(yīng)用程序可以使用補(bǔ)充視圖來給每個單元格自定的文本標(biāo)簽來顯示關(guān)于該單元格的信息。和集合視圖單元格一樣,補(bǔ)充視圖有回收機(jī)制,以優(yōu)化集合視圖所使用的資源數(shù)量。因此,在你的應(yīng)用程序中使用的所有補(bǔ)充視圖,都應(yīng)該繼承自UICollectionReusableView類。
將補(bǔ)充視圖添加到布局的步驟如下:
- 使用
registerClass:forSupplementaryViewOfKind:withReuseIdentifier:或registerNib:forSupplementaryViewOfKind:withReuseIdentifier:方法注冊補(bǔ)充視圖到集合視圖的布局對象 - 在你的數(shù)據(jù)源中,實(shí)現(xiàn)
collectionView:viewForSupplementaryElementOfKind:atIndexPath:方法。因?yàn)檫@些視圖是重用的,調(diào)用dequeueReusableSupplementaryViewOfKind:withReuseIdentifier:forIndexPath:來獲取,或者創(chuàng)建一個新的重用視圖,并在返回前設(shè)置必要的數(shù)據(jù)。 - 為你的補(bǔ)充視圖創(chuàng)建布局屬性,就像為單元格做這些一樣。
- 通過
layoutAttributesForElementsInRect:方法返回一個數(shù)組,該數(shù)組包含這些布局屬性對象。 - 實(shí)現(xiàn)
layoutAttributesForSupplementaryViewOfKind:atIndexPath:方法為特定補(bǔ)充視圖每當(dāng)查詢時返回屬性對象。
在自定義布局中為補(bǔ)充視圖創(chuàng)建屬性對象的過程是幾乎與單元格的過程相同,不同之處在于自定義布局可以有多種類型的補(bǔ)充視圖,而單元格的類型限制為一種。這是因?yàn)檠a(bǔ)充視圖旨在增強(qiáng)主要內(nèi)容,因此與它分離。有許多方法可以補(bǔ)充應(yīng)用程序的內(nèi)容,因此每個補(bǔ)充視圖的方法都會指定要處理哪種視圖以區(qū)分其他視圖,并允許布局根據(jù)其類型正確計(jì)算其屬性。當(dāng)注冊一個補(bǔ)充視圖來使用時,你提供使用的字符串通過布局對象來區(qū)分來自于其他的視圖。有關(guān)將補(bǔ)充視圖合并到自定義布局中的示例,請看Incorporating Supplementary Views
在自定義布局中包含裝飾視圖
裝飾視圖是增強(qiáng)集合視圖布局外觀的視覺裝飾。不像單元格和補(bǔ)充視圖,裝飾視圖僅提供可視內(nèi)容,因此獨(dú)立于數(shù)據(jù)源。你可以使用它們來提供自定義背景,填充單元格之間的空間,或者甚至模糊你想要的單元格。裝飾視圖僅由布局對象定義和管理,不與集合視圖的數(shù)據(jù)源對象交互。
要將裝飾視圖添加到布局中,請執(zhí)行以下操作:
- 使用
registerClass:forDecorationViewOfKind:或registerNib:forDecorationViewOfKind:方法使用布局對象注冊你的裝飾視圖。雖然這個過程有點(diǎn)像注冊單元格和補(bǔ)充視圖,但記住注冊裝飾視圖是發(fā)生在布局對象上,而與數(shù)據(jù)源無關(guān)。 - 在你的布局對象的
layoutAttributesForElementsInRect:方法中,為裝飾視圖創(chuàng)建屬性,就像為單元格和補(bǔ)充視圖那樣做一樣。 - 在你的布局對象中實(shí)現(xiàn)
layoutAttributesForDecorationViewOfKind:atIndexPath:方法,并當(dāng)詢問時返回裝飾視圖的屬性。 - 可選的,實(shí)現(xiàn)
initialLayoutAttributesForAppearingDecorationElementOfKind:atIndexPath:和finalLayoutAttributesForDisappearingDecorationElementOfKind:atIndexPath:方法來處理動畫為裝飾視圖的出現(xiàn)和消失。關(guān)于更多信息,請看Making Insertion and Deletion Animations More Interesting
創(chuàng)建裝飾視圖的過程與單元格和補(bǔ)充視圖的過程不同。注冊類或nib文件是需要做的,以確保在需要的時候創(chuàng)建裝飾視圖。因?yàn)樗鼈兗兇馐且曈X的,裝飾視圖不需要超出在提供的nib文件或?qū)ο蟮?code>initWithFrame:方法中已經(jīng)完成的任何配置。因此,當(dāng)需要裝飾視圖時,集合視圖為你創(chuàng)建并應(yīng)用布局對象提供的屬性。任何裝飾視圖都應(yīng)該繼承自UICollectionReusableView,因?yàn)椴季謱ο笫褂闷溲b飾視圖的回收機(jī)制。
注意:當(dāng)為你的裝飾視圖創(chuàng)建屬性時,不要忘記考慮
zIndex屬性。你可以使用zIndex屬性將顯示的單元格和補(bǔ)充視圖背后(或者,如果你愿意的話)層疊你的裝飾視圖。
使插入和刪除動畫更有趣
插入和刪除單元格和視圖在布局過程中構(gòu)成了一個有趣的挑戰(zhàn)。插入單元格可能會導(dǎo)致其他單元格和視圖的布局更改。即使布局對象知道如何將現(xiàn)有單元格和視圖從當(dāng)前位置設(shè)置為新位置,但它沒有插入單元格的當(dāng)前位置。代替插入一個新的單元格沒有動畫效果,集合視圖會詢問布局對象來提供一組用于動畫的初始屬性。相似的,當(dāng)單元格被刪除時,集合視圖會詢問布局對象來提供用于任何動畫的端點(diǎn)的一組最終屬性。
為了理解初始屬性的工作原理,可以看一個示例。起始布局(圖5-3)顯示了最初只包含三個單元格的集合視圖。當(dāng)一個新的單元格被插入時,集合視圖會詢問布局對象來提供初始屬性為被插入的單元格。在這種情況下,布局對象會將單元格的起始位置設(shè)置在集合視圖的中心,并設(shè)置它的透明度值為0來隱藏它。在動畫期間,這個新單元格會淡出并從集合視圖的中心移動到右下角的最終位置。

清單5-2顯示了如圖5-3所示可以用來指定插入單元格的初始屬性的代碼。此方法將單元格的位置設(shè)置為集合視圖的中心,并使其透明。然后,布局對象將作為常規(guī)布局過程的一部分,為單元格提供最終位置和alpha值。
清單5-2 指定插入單元格的初始屬性
- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath {
UICollectionViewLayoutAttributes* attributes = [self layoutAttributesForItemAtIndexPath:itemIndexPath];
attributes.alpha = 0.0;
CGSize size = [self collectionView].frame.size;
attributes.center = CGPointMake(size.width / 2.0, size.height / 2.0);
return attributes;
}
注意:列表5-2將在插入一個單元格時對所有單元格進(jìn)行動畫處理,因此在插入之前已經(jīng)存在的三個單元格也將從集合視圖的中心彈出。要僅動畫所插入的單元格,請檢查item的索引路徑是否與傳遞給
prepareForCollectionViewUpdates:方法的item的索引路徑匹配,并且僅在找到匹配項(xiàng)時才執(zhí)行動畫。否則,返回通過調(diào)用initialLayoutAttributesForAppearingItemAtIndexPath的super方法返回的屬性。
處理刪除的過程與插入過程相同,只是您指定最終屬性而不是初始屬性。從上一個示例中,如果您使用與插入單元格時使用的相同的屬性,則刪除單元格將導(dǎo)致它在移動到集合視圖的中心時淡出。在UICollectionViewLayout類中有六種方法可用于item,補(bǔ)充視圖和裝飾視圖的兩個獨(dú)立方法(初始和最終屬性)。
改善布局的滾動體驗(yàn)
自定義布局對象可以影響集合視圖的滾動行為,以創(chuàng)建更好的用戶體驗(yàn)。當(dāng)滾動相關(guān)觸摸事件結(jié)束時,滾動視圖根據(jù)當(dāng)前的實(shí)際速度和減速率確定滾動內(nèi)容的最終靜止位置。當(dāng)集合視圖知道該位置時,如果位置應(yīng)該被改變它會詢問布局對象通過調(diào)用它的targetContentOffsetForProposedContentOffset:withScrollingVelocity:方法。因?yàn)樗诨A(chǔ)內(nèi)容仍然移動時調(diào)用此方法,自定義布局可能會影響滾動內(nèi)容的最終位置。
圖5-4演示了如何使用布局對象來更改集合視圖的滾動行為。假設(shè)集合視圖偏移從(0,0)開始,用戶向左滑動。集合視圖計(jì)算滾動自然停止的位置,并將該值提供為“建議”內(nèi)容偏移值。您的布局對象可能會更改建議值,以確保在滾動停止時,item將精確集中在集合視圖的可見邊界。這個新值將成為目標(biāo)內(nèi)容偏移,并且時從targetContentOffsetForProposedContentOffset:withScrollingVelocity:返回。

實(shí)現(xiàn)自定義布局的提示
以下是實(shí)現(xiàn)自定義布局對象的一些提示和建議:
- 考慮使用
prepareLayout方法來創(chuàng)建和存儲以后需要的UICollectionViewLayoutAttributes對象。集合視圖將在某個時候詢問布局屬性對象,因此在某些情況下,可以在前面創(chuàng)建和存儲它們。如果您的items數(shù)量相對較少(幾百個)或這些items的實(shí)際布局屬性不會頻繁更改,則尤其如此。但是,如果您的布局需要管理數(shù)千個items,則需要權(quán)衡緩存和重新計(jì)算的優(yōu)勢。對于其布局不經(jīng)常更改的可變大小items,緩存通常不需要定期重新計(jì)算復(fù)雜的布局信息。對于大量固定大小的items,可以根據(jù)需要計(jì)算屬性更簡單。而對于屬性頻繁更改的items,您可能會重新計(jì)算所有時間,因此緩存可能只占用內(nèi)存中的額外空間。 - 避免子類化
UICollectionView。集合視圖有很少或沒有自己的外觀。相反,它從數(shù)據(jù)源對象和布局對象的所有布局相關(guān)信息中提取其所有視圖。如果您嘗試在三維中布置items,正確的方法是實(shí)現(xiàn)一個自定義布局,以便設(shè)置每個單元格的3D變換并正確查看。 - 不要從您的自定義布局對象的
layoutAttributesForElementsInRect:方法調(diào)用UICollectionView的visibleCells方法。集合視圖對于items的位置一無所知,除非布局對象告訴它。所以詢問可見單元格只是將請求轉(zhuǎn)發(fā)到你的布局對象上。您的布局對象應(yīng)始終知道內(nèi)容區(qū)域中items的位置,并且可以隨時返回這些items的屬性。在大多數(shù)情況下,它應(yīng)該自己做。在有限的情況下,布局對象可能依賴于數(shù)據(jù)源中的信息來定位items。例如,在地圖上顯示items的布局可能會從數(shù)據(jù)源中檢索每個item的地圖位置。
官方文檔地址
Creating Custom Layouts